@cursor/july 0.1.111 → 0.1.112

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 (383) hide show
  1. package/dist/bin/agent-serve.js +18 -1
  2. package/dist/channels/github/github-channel.d.ts +29 -19
  3. package/dist/channels/github/github-channel.d.ts.map +1 -1
  4. package/dist/channels/github/github-channel.js +29 -19
  5. package/dist/channels/slack/agentic-delivery.d.ts.map +1 -1
  6. package/dist/channels/slack/agentic-delivery.js +2 -0
  7. package/dist/channels/slack/dispatch.d.ts +11 -1
  8. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  9. package/dist/channels/slack/dispatch.js +142 -39
  10. package/dist/channels/slack/placeholder.d.ts +26 -0
  11. package/dist/channels/slack/placeholder.d.ts.map +1 -1
  12. package/dist/channels/slack/placeholder.js +28 -0
  13. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  14. package/dist/channels/slack/slack-channel.js +9 -16
  15. package/dist/docs/404.html +2 -2
  16. package/dist/docs/assets/{app.Drol6mi6.js → app.DxTdhphC.js} +4 -4
  17. package/dist/docs/assets/building-with-agents.md.BBCx0AUo.js +9 -0
  18. package/dist/docs/assets/building-with-agents.md.BBCx0AUo.lean.js +1 -0
  19. package/dist/docs/assets/chunks/@localSearchIndexroot.QmjDU6Jh.js +1 -0
  20. package/dist/docs/assets/chunks/{VPLocalSearchBox.CdqoBZJX.js → VPLocalSearchBox.CR3KTF0X.js} +1 -1
  21. package/dist/docs/assets/chunks/{arc.BVX3ycTn.js → arc.CVVqBOdS.js} +1 -1
  22. package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.CcChnMxX.js → architectureDiagram-Q4EWVU46.CJHGP4ki.js} +1 -1
  23. package/dist/docs/assets/chunks/{baseUniq.xwtXO-yt.js → baseUniq.r7UVVRBP.js} +1 -1
  24. package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.CijZ_taK.js → blockDiagram-DXYQGD6D.DKmMaTre.js} +1 -1
  25. package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.0FBvwBvK.js → c4Diagram-AHTNJAMY.DDJsntUO.js} +1 -1
  26. package/dist/docs/assets/chunks/channel.BjpoSbz_.js +1 -0
  27. package/dist/docs/assets/chunks/{chunk-4BX2VUAB.CELMmMDA.js → chunk-4BX2VUAB.BK2rKt6W.js} +1 -1
  28. package/dist/docs/assets/chunks/{chunk-4TB4RGXK.C4bhFtSm.js → chunk-4TB4RGXK.DRLV8RnF.js} +1 -1
  29. package/dist/docs/assets/chunks/{chunk-55IACEB6.ZnQ9gRRQ.js → chunk-55IACEB6.DaKjxtb7.js} +1 -1
  30. package/dist/docs/assets/chunks/{chunk-EDXVE4YY.DPlmglG-.js → chunk-EDXVE4YY.C5sPCIT1.js} +1 -1
  31. package/dist/docs/assets/chunks/{chunk-FMBD7UC4.BrUk8pff.js → chunk-FMBD7UC4.CSGWyNTB.js} +1 -1
  32. package/dist/docs/assets/chunks/{chunk-OYMX7WX6.CcmWIncu.js → chunk-OYMX7WX6.D5tK9XEr.js} +1 -1
  33. package/dist/docs/assets/chunks/{chunk-QZHKN3VN.D65-cs8I.js → chunk-QZHKN3VN.BeZGd1UZ.js} +1 -1
  34. package/dist/docs/assets/chunks/{chunk-YZCP3GAM.qoXZpG9F.js → chunk-YZCP3GAM.U_tfWwQR.js} +1 -1
  35. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.BgxOlMHw.js +1 -0
  36. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.BgxOlMHw.js +1 -0
  37. package/dist/docs/assets/chunks/clone.DRuGBKZC.js +1 -0
  38. package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.8rYtqudO.js → cose-bilkent-S5V4N54A.DVeRXIb6.js} +1 -1
  39. package/dist/docs/assets/chunks/{dagre-KV5264BT.DrRP1fOh.js → dagre-KV5264BT.BpKJAeRZ.js} +1 -1
  40. package/dist/docs/assets/chunks/{diagram-5BDNPKRD.DHj_xA2_.js → diagram-5BDNPKRD.BQOtrd1Z.js} +1 -1
  41. package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.Bz_6nAKj.js → diagram-G4DWMVQ6.CSDAhjPI.js} +1 -1
  42. package/dist/docs/assets/chunks/{diagram-MMDJMWI5.BWA0xSW9.js → diagram-MMDJMWI5.Dpztst2S.js} +1 -1
  43. package/dist/docs/assets/chunks/{diagram-TYMM5635.CpTJLNJI.js → diagram-TYMM5635.qJHRizHR.js} +1 -1
  44. package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.-7AWWSrP.js → erDiagram-SMLLAGMA.vbDotH3l.js} +1 -1
  45. package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.BTnQ742_.js → flowDiagram-DWJPFMVM.CqS_ZQr4.js} +1 -1
  46. package/dist/docs/assets/chunks/framework.BNw1pucY.js +19 -0
  47. package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.B5_HiiQ5.js → ganttDiagram-T4ZO3ILL.DTLdR4pN.js} +1 -1
  48. package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.CZcNTFZd.js → gitGraphDiagram-UUTBAWPF.D04lnbnr.js} +1 -1
  49. package/dist/docs/assets/chunks/{graph.V2GLaab4.js → graph.BlfqLJsM.js} +1 -1
  50. package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.7pZOkCCU.js → infoDiagram-42DDH7IO.tAooImWA.js} +1 -1
  51. package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DSMo3Qa3.js → ishikawaDiagram-UXIWVN3A.ClUsVqnJ.js} +1 -1
  52. package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.BNEgWN1S.js → journeyDiagram-VCZTEJTY.C3tUgyCg.js} +1 -1
  53. package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.B-4d4tC7.js → kanban-definition-6JOO6SKY.CtD9-QCe.js} +1 -1
  54. package/dist/docs/assets/chunks/{layout.Dvbn9nSb.js → layout.D38U-LnT.js} +1 -1
  55. package/dist/docs/assets/chunks/{linear.D2GM4p4b.js → linear.BJmssyhN.js} +1 -1
  56. package/dist/docs/assets/chunks/{min.DVBtLK-B.js → min.DNgXoouU.js} +1 -1
  57. package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.CnJRI55x.js → mindmap-definition-QFDTVHPH.Dcp6cxeu.js} +1 -1
  58. package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.CtoaTFlA.js → pieDiagram-DEJITSTG.CLDw6zIs.js} +1 -1
  59. package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.DtT24_vN.js → quadrantDiagram-34T5L4WZ.CYaeeY4c.js} +1 -1
  60. package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.CjSO4o8f.js → requirementDiagram-MS252O5E.gMYuRpq2.js} +1 -1
  61. package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.-wWiIVWa.js → sankeyDiagram-XADWPNL6.CZqyHFbc.js} +1 -1
  62. package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.DSk8s4gX.js → sequenceDiagram-FGHM5R23.BTsCjUDN.js} +1 -1
  63. package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.BFKAsdkN.js → stateDiagram-FHFEXIEX.CftT9mLJ.js} +1 -1
  64. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.-43J68xB.js +1 -0
  65. package/dist/docs/assets/chunks/{theme.C0MctGaz.js → theme.B_7J9ZsV.js} +2 -2
  66. package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.TUNJbAFe.js → timeline-definition-GMOUNBTQ.DbU3WUNw.js} +1 -1
  67. package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.C-RGNnk4.js → vennDiagram-DHZGUBPP.ixsq-q2u.js} +1 -1
  68. package/dist/docs/assets/chunks/wardley-RL74JXVD.WRXz-Dux.js +162 -0
  69. package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.DH4zt73Y.js → wardleyDiagram-NUSXRM2D.C0ewvgbp.js} +1 -1
  70. package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.B-3k6bF6.js → xychartDiagram-5P7HB3ND.nAEhF4bO.js} +1 -1
  71. package/dist/docs/assets/deployment.md.D2jQZuFx.js +32 -0
  72. package/dist/docs/assets/deployment.md.D2jQZuFx.lean.js +1 -0
  73. package/dist/docs/assets/evals.md.BYvfZ-PO.js +72 -0
  74. package/dist/docs/assets/evals.md.BYvfZ-PO.lean.js +1 -0
  75. package/dist/docs/assets/guides_agent-to-agent.md.8oDTfu-E.js +30 -0
  76. package/dist/docs/assets/guides_agent-to-agent.md.8oDTfu-E.lean.js +1 -0
  77. package/dist/docs/assets/guides_bitbucket.md.mpevW-VP.js +145 -0
  78. package/dist/docs/assets/guides_bitbucket.md.mpevW-VP.lean.js +1 -0
  79. package/dist/docs/assets/guides_cloud-agents.md.Cp1O3u-X.js +15 -0
  80. package/dist/docs/assets/guides_cloud-agents.md.Cp1O3u-X.lean.js +1 -0
  81. package/dist/docs/assets/guides_convert-automation.md.CqEyfP6Y.js +43 -0
  82. package/dist/docs/assets/guides_convert-automation.md.CqEyfP6Y.lean.js +1 -0
  83. package/dist/docs/assets/guides_github.md.BwpBp3ed.js +156 -0
  84. package/dist/docs/assets/guides_github.md.BwpBp3ed.lean.js +1 -0
  85. package/dist/docs/assets/guides_gitlab.md.DaEC3nMk.js +153 -0
  86. package/dist/docs/assets/guides_gitlab.md.DaEC3nMk.lean.js +1 -0
  87. package/dist/docs/assets/guides_grokbot-agents.md.CMhZNdEU.js +16 -0
  88. package/dist/docs/assets/guides_grokbot-agents.md.CMhZNdEU.lean.js +1 -0
  89. package/dist/docs/assets/guides_improve.md.Bnp4F99w.js +22 -0
  90. package/dist/docs/assets/guides_improve.md.Bnp4F99w.lean.js +1 -0
  91. package/dist/docs/assets/guides_mcp-oauth.md.bSFakfCY.js +50 -0
  92. package/dist/docs/assets/guides_mcp-oauth.md.bSFakfCY.lean.js +1 -0
  93. package/dist/docs/assets/guides_opentelemetry.md.BKDxQmmd.js +35 -0
  94. package/dist/docs/assets/guides_opentelemetry.md.BKDxQmmd.lean.js +1 -0
  95. package/dist/docs/assets/guides_slack.md.Bo96y42E.js +70 -0
  96. package/dist/docs/assets/guides_slack.md.Bo96y42E.lean.js +1 -0
  97. package/dist/docs/assets/guides_webhooks.md.1A72_VEE.js +92 -0
  98. package/dist/docs/assets/guides_webhooks.md.1A72_VEE.lean.js +1 -0
  99. package/dist/docs/assets/hillclimbing.md.D4E1o5Sa.js +7 -0
  100. package/dist/docs/assets/hillclimbing.md.D4E1o5Sa.lean.js +1 -0
  101. package/dist/docs/assets/{index.md.BFVyY2KT.js → index.md.C-t81M5J.js} +2 -2
  102. package/dist/docs/assets/{index.md.BFVyY2KT.lean.js → index.md.C-t81M5J.lean.js} +1 -1
  103. package/dist/docs/assets/{quickstart.md.D3MjSZN-.js → quickstart.md.DAvVhuuU.js} +1 -1
  104. package/dist/docs/assets/{quickstart.md.D3MjSZN-.lean.js → quickstart.md.DAvVhuuU.lean.js} +1 -1
  105. package/dist/docs/assets/{reference_agent-config.md.CfVA-LZJ.js → reference_agent-config.md.DGPyw7ms.js} +1 -1
  106. package/dist/docs/assets/{reference_agent-config.md.CfVA-LZJ.lean.js → reference_agent-config.md.DGPyw7ms.lean.js} +1 -1
  107. package/dist/docs/assets/{reference_artifacts.md.Vf7qyIZ-.js → reference_artifacts.md.Bu_4HmsD.js} +1 -1
  108. package/dist/docs/assets/{reference_artifacts.md.Vf7qyIZ-.lean.js → reference_artifacts.md.Bu_4HmsD.lean.js} +1 -1
  109. package/dist/docs/assets/{reference_channels.md.icqLKcTc.js → reference_channels.md.nFWbzAic.js} +1 -1
  110. package/dist/docs/assets/{reference_channels.md.icqLKcTc.lean.js → reference_channels.md.nFWbzAic.lean.js} +1 -1
  111. package/dist/docs/assets/{reference_cli.md.B2dBL6L8.js → reference_cli.md.DLWDz9ij.js} +3 -1
  112. package/dist/docs/assets/{reference_cli.md.B2dBL6L8.lean.js → reference_cli.md.DLWDz9ij.lean.js} +1 -1
  113. package/dist/docs/assets/{reference_connections.md.Cb3U_c8n.js → reference_connections.md.CmyrlXfY.js} +1 -1
  114. package/dist/docs/assets/{reference_connections.md.Cb3U_c8n.lean.js → reference_connections.md.CmyrlXfY.lean.js} +1 -1
  115. package/dist/docs/assets/reference_evals.md.DNJzM_yf.js +57 -0
  116. package/dist/docs/assets/reference_evals.md.DNJzM_yf.lean.js +1 -0
  117. package/dist/docs/assets/reference_extensions.md.Ceq-qT8d.js +58 -0
  118. package/dist/docs/assets/reference_extensions.md.Ceq-qT8d.lean.js +1 -0
  119. package/dist/docs/assets/{reference_hooks.md.CZuynAxj.js → reference_hooks.md.B7uzNENk.js} +2 -2
  120. package/dist/docs/assets/{reference_hooks.md.CZuynAxj.lean.js → reference_hooks.md.B7uzNENk.lean.js} +1 -1
  121. package/dist/docs/assets/{reference_http-api.md.DTKcYE6L.js → reference_http-api.md.CduHavZ2.js} +1 -1
  122. package/dist/docs/assets/{reference_http-api.md.DTKcYE6L.lean.js → reference_http-api.md.CduHavZ2.lean.js} +1 -1
  123. package/dist/docs/assets/{reference_instructions.md.D7gkckK-.js → reference_instructions.md.CU1My5My.js} +1 -1
  124. package/dist/docs/assets/{reference_instructions.md.D7gkckK-.lean.js → reference_instructions.md.CU1My5My.lean.js} +1 -1
  125. package/dist/docs/assets/{reference_playground.md.D2YExv5K.js → reference_playground.md.Ch2d0Iqi.js} +1 -1
  126. package/dist/docs/assets/{reference_playground.md.D2YExv5K.lean.js → reference_playground.md.Ch2d0Iqi.lean.js} +1 -1
  127. package/dist/docs/assets/{reference_project-layout.md.DPxbUJyt.js → reference_project-layout.md.BGhgpy9V.js} +1 -1
  128. package/dist/docs/assets/{reference_project-layout.md.DPxbUJyt.lean.js → reference_project-layout.md.BGhgpy9V.lean.js} +1 -1
  129. package/dist/docs/assets/{reference_prompt.md.BQ5uAv1F.js → reference_prompt.md.Ccp0R53H.js} +1 -1
  130. package/dist/docs/assets/{reference_prompt.md.BQ5uAv1F.lean.js → reference_prompt.md.Ccp0R53H.lean.js} +1 -1
  131. package/dist/docs/assets/{reference_schedules.md.BasfZWO-.js → reference_schedules.md.B2Nm6FaD.js} +1 -1
  132. package/dist/docs/assets/{reference_schedules.md.BasfZWO-.lean.js → reference_schedules.md.B2Nm6FaD.lean.js} +1 -1
  133. package/dist/docs/assets/{reference_sessions.md.YKvIsWAx.js → reference_sessions.md.1_6Vyv7x.js} +1 -1
  134. package/dist/docs/assets/{reference_sessions.md.YKvIsWAx.lean.js → reference_sessions.md.1_6Vyv7x.lean.js} +1 -1
  135. package/dist/docs/assets/{reference_skills.md.rNgpsGd0.js → reference_skills.md.DjQkRefx.js} +1 -1
  136. package/dist/docs/assets/{reference_skills.md.rNgpsGd0.lean.js → reference_skills.md.DjQkRefx.lean.js} +1 -1
  137. package/dist/docs/assets/{reference_subagents.md.e5qitjJt.js → reference_subagents.md.BHsSMMyO.js} +1 -1
  138. package/dist/docs/assets/{reference_subagents.md.e5qitjJt.lean.js → reference_subagents.md.BHsSMMyO.lean.js} +1 -1
  139. package/dist/docs/assets/{reference_tools.md.BdCO2aHZ.js → reference_tools.md.BYzUTeVA.js} +1 -1
  140. package/dist/docs/assets/{reference_tools.md.BdCO2aHZ.lean.js → reference_tools.md.BYzUTeVA.lean.js} +1 -1
  141. package/dist/docs/assets/{templates_agentic-owners.md.Da_AGDlH.js → templates_agentic-owners.md.9M575F5C.js} +1 -1
  142. package/dist/docs/assets/{templates_agentic-owners.md.Da_AGDlH.lean.js → templates_agentic-owners.md.9M575F5C.lean.js} +1 -1
  143. package/dist/docs/assets/{templates_pr-autofixer.md.DqxocIGh.js → templates_pr-autofixer.md.ws0DDXDy.js} +1 -1
  144. package/dist/docs/assets/{templates_pr-autofixer.md.DqxocIGh.lean.js → templates_pr-autofixer.md.ws0DDXDy.lean.js} +1 -1
  145. package/dist/docs/assets/{templates_security-reviewer.md.Bhnvd8VE.js → templates_security-reviewer.md.KEFYXzfK.js} +1 -1
  146. package/dist/docs/assets/{templates_security-reviewer.md.Bhnvd8VE.lean.js → templates_security-reviewer.md.KEFYXzfK.lean.js} +1 -1
  147. package/dist/docs/assets/templates_thermo-quality-review.md.VNJ_mohX.js +3 -0
  148. package/dist/docs/assets/templates_thermo-quality-review.md.VNJ_mohX.lean.js +1 -0
  149. package/dist/docs/assets/templates_thermo-review.md.Hi3zWOkP.js +3 -0
  150. package/dist/docs/assets/templates_thermo-review.md.Hi3zWOkP.lean.js +1 -0
  151. package/dist/docs/assets/{templates_triage.md.BdBWO9Ic.js → templates_triage.md.CVGe_FG6.js} +1 -1
  152. package/dist/docs/assets/{templates_triage.md.BdBWO9Ic.lean.js → templates_triage.md.CVGe_FG6.lean.js} +1 -1
  153. package/dist/docs/assets/troubleshooting.md.mnfFG2Em.js +1 -0
  154. package/dist/docs/assets/troubleshooting.md.mnfFG2Em.lean.js +1 -0
  155. package/dist/docs/building-with-agents.html +44 -48
  156. package/dist/docs/building-with-agents.md +94 -82
  157. package/dist/docs/deployment.html +59 -78
  158. package/dist/docs/deployment.md +117 -363
  159. package/dist/docs/evals.html +85 -224
  160. package/dist/docs/evals.md +146 -673
  161. package/dist/docs/guides/agent-to-agent.html +58 -42
  162. package/dist/docs/guides/agent-to-agent.md +112 -35
  163. package/dist/docs/guides/bitbucket.html +179 -44
  164. package/dist/docs/guides/bitbucket.md +249 -48
  165. package/dist/docs/guides/cloud-agents.html +46 -40
  166. package/dist/docs/guides/cloud-agents.md +119 -66
  167. package/dist/docs/guides/convert-automation.html +80 -49
  168. package/dist/docs/guides/convert-automation.md +156 -147
  169. package/dist/docs/guides/github.html +184 -92
  170. package/dist/docs/guides/github.md +260 -245
  171. package/dist/docs/guides/gitlab.html +184 -45
  172. package/dist/docs/guides/gitlab.md +249 -50
  173. package/dist/docs/guides/grokbot-agents.html +48 -41
  174. package/dist/docs/guides/grokbot-agents.md +99 -53
  175. package/dist/docs/guides/improve.html +48 -40
  176. package/dist/docs/guides/improve.md +111 -58
  177. package/dist/docs/guides/mcp-oauth.html +74 -52
  178. package/dist/docs/guides/mcp-oauth.md +111 -121
  179. package/dist/docs/guides/opentelemetry.html +63 -54
  180. package/dist/docs/guides/opentelemetry.md +96 -165
  181. package/dist/docs/guides/slack.html +83 -59
  182. package/dist/docs/guides/slack.md +157 -227
  183. package/dist/docs/guides/webhooks.html +97 -230
  184. package/dist/docs/guides/webhooks.md +154 -385
  185. package/dist/docs/hashmap.json +1 -1
  186. package/dist/docs/hillclimbing.html +44 -38
  187. package/dist/docs/hillclimbing.md +101 -55
  188. package/dist/docs/index.html +38 -38
  189. package/dist/docs/index.md +2 -0
  190. package/dist/docs/llms-full.txt +3082 -3104
  191. package/dist/docs/llms.txt +21 -18
  192. package/dist/docs/quickstart.html +37 -37
  193. package/dist/docs/reference/agent-config.html +37 -37
  194. package/dist/docs/reference/artifacts.html +38 -38
  195. package/dist/docs/reference/channels.html +37 -37
  196. package/dist/docs/reference/cli.html +39 -37
  197. package/dist/docs/reference/cli.md +2 -0
  198. package/dist/docs/reference/connections.html +37 -37
  199. package/dist/docs/reference/evals.html +116 -0
  200. package/dist/docs/reference/evals.md +293 -0
  201. package/dist/docs/reference/extensions.html +80 -84
  202. package/dist/docs/reference/extensions.md +127 -199
  203. package/dist/docs/reference/hooks.html +39 -39
  204. package/dist/docs/reference/hooks.md +34 -34
  205. package/dist/docs/reference/http-api.html +37 -37
  206. package/dist/docs/reference/instructions.html +37 -37
  207. package/dist/docs/reference/playground.html +37 -37
  208. package/dist/docs/reference/project-layout.html +37 -37
  209. package/dist/docs/reference/prompt.html +37 -37
  210. package/dist/docs/reference/schedules.html +37 -37
  211. package/dist/docs/reference/sessions.html +37 -37
  212. package/dist/docs/reference/skills.html +37 -37
  213. package/dist/docs/reference/subagents.html +37 -37
  214. package/dist/docs/reference/tools.html +37 -37
  215. package/dist/docs/templates/agentic-owners.html +38 -38
  216. package/dist/docs/templates/pr-autofixer.html +37 -37
  217. package/dist/docs/templates/security-reviewer.html +38 -38
  218. package/dist/docs/templates/thermo-quality-review.html +62 -0
  219. package/dist/docs/templates/thermo-quality-review.md +75 -0
  220. package/dist/docs/templates/thermo-review.html +62 -0
  221. package/dist/docs/templates/thermo-review.md +74 -0
  222. package/dist/docs/templates/triage.html +37 -37
  223. package/dist/docs/troubleshooting.html +38 -38
  224. package/dist/docs/troubleshooting.md +97 -66
  225. package/dist/extensions/cursor-cloud-agents/skills/handoff.md +3 -7
  226. package/dist/extensions/improve/extension.d.ts +3 -1
  227. package/dist/extensions/improve/extension.d.ts.map +1 -1
  228. package/dist/extensions/improve/extension.js +4 -2
  229. package/dist/extensions/improve/skills/yourself.js +1 -1
  230. package/dist/filesystem.d.ts +46 -2
  231. package/dist/filesystem.d.ts.map +1 -1
  232. package/dist/filesystem.js +149 -102
  233. package/dist/index.d.ts +2 -2
  234. package/dist/index.d.ts.map +1 -1
  235. package/dist/index.js +1 -1
  236. package/dist/internal/cli-ax.d.ts +6 -0
  237. package/dist/internal/cli-ax.d.ts.map +1 -1
  238. package/dist/internal/cli-ax.js +72 -14
  239. package/dist/internal/continuation-identity.d.ts.map +1 -1
  240. package/dist/internal/continuation-identity.js +1 -0
  241. package/dist/internal/cursor-agent-template.d.ts +1 -1
  242. package/dist/internal/cursor-agent-template.d.ts.map +1 -1
  243. package/dist/internal/cursor-agent-template.js +2 -0
  244. package/dist/internal/filesystem/tools.d.ts.map +1 -1
  245. package/dist/internal/filesystem/tools.js +2 -2
  246. package/dist/internal/filesystem/walk.d.ts +7 -4
  247. package/dist/internal/filesystem/walk.d.ts.map +1 -1
  248. package/dist/internal/filesystem/walk.js +34 -11
  249. package/dist/internal/hosted-admission-adapter.d.ts +3 -0
  250. package/dist/internal/hosted-admission-adapter.d.ts.map +1 -1
  251. package/dist/internal/hosted-delivery-protocol.d.ts +17 -0
  252. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  253. package/dist/internal/hosted-delivery-protocol.js +50 -1
  254. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  255. package/dist/internal/hosted-delivery.js +8 -0
  256. package/dist/internal/init-project.d.ts.map +1 -1
  257. package/dist/internal/init-project.js +4 -0
  258. package/dist/internal/server.d.ts.map +1 -1
  259. package/dist/internal/server.js +94 -39
  260. package/dist/internal/session-engine.d.ts.map +1 -1
  261. package/dist/internal/session-engine.js +11 -5
  262. package/dist/internal/skill-catalog.d.ts +28 -0
  263. package/dist/internal/skill-catalog.d.ts.map +1 -0
  264. package/dist/internal/skill-catalog.js +44 -0
  265. package/dist/playground/assets/index-B1c1LeIf.js +67 -0
  266. package/dist/playground/assets/index-CK2LX3iD.css +1 -0
  267. package/dist/playground/index.html +2 -2
  268. package/dist/types.d.ts +9 -0
  269. package/dist/types.d.ts.map +1 -1
  270. package/docs/README.md +2 -0
  271. package/docs/building-with-agents.md +96 -84
  272. package/docs/deployment.md +118 -364
  273. package/docs/evals.md +147 -674
  274. package/docs/guides/agent-to-agent.md +113 -36
  275. package/docs/guides/bitbucket.md +250 -49
  276. package/docs/guides/cloud-agents.md +119 -67
  277. package/docs/guides/convert-automation.md +157 -148
  278. package/docs/guides/github.md +261 -246
  279. package/docs/guides/gitlab.md +250 -51
  280. package/docs/guides/grokbot-agents.md +100 -55
  281. package/docs/guides/improve.md +112 -59
  282. package/docs/guides/mcp-oauth.md +112 -122
  283. package/docs/guides/opentelemetry.md +97 -166
  284. package/docs/guides/slack.md +158 -228
  285. package/docs/guides/webhooks.md +155 -386
  286. package/docs/hillclimbing.md +102 -56
  287. package/docs/reference/cli.md +2 -0
  288. package/docs/reference/evals.md +298 -0
  289. package/docs/reference/extensions.md +128 -200
  290. package/docs/reference/hooks.md +34 -34
  291. package/docs/templates/thermo-quality-review.md +80 -0
  292. package/docs/templates/thermo-review.md +79 -0
  293. package/docs/troubleshooting.md +98 -67
  294. package/package.json +1 -1
  295. package/skills/github/SKILL.md +21 -13
  296. package/src/bin/agent-serve.ts +22 -0
  297. package/src/channels/github/github-channel.ts +29 -19
  298. package/src/channels/slack/agentic-delivery.ts +2 -0
  299. package/src/channels/slack/dispatch.ts +126 -4
  300. package/src/channels/slack/placeholder.ts +51 -0
  301. package/src/channels/slack/slack-channel.ts +9 -2
  302. package/src/extensions/cursor-cloud-agents/skills/handoff.md +3 -7
  303. package/src/extensions/improve/extension.ts +4 -2
  304. package/src/extensions/improve/skills/yourself.ts +1 -1
  305. package/src/filesystem.ts +168 -65
  306. package/src/index.ts +3 -0
  307. package/src/internal/cli-ax.ts +88 -15
  308. package/src/internal/continuation-identity.ts +1 -0
  309. package/src/internal/cursor-agent-template.ts +2 -0
  310. package/src/internal/filesystem/tools.ts +2 -0
  311. package/src/internal/filesystem/walk.ts +60 -15
  312. package/src/internal/hosted-admission-adapter.ts +3 -0
  313. package/src/internal/hosted-delivery-protocol.ts +78 -1
  314. package/src/internal/hosted-delivery.ts +8 -0
  315. package/src/internal/init-project.ts +4 -0
  316. package/src/internal/server.ts +104 -41
  317. package/src/internal/session-engine.ts +16 -4
  318. package/src/internal/skill-catalog.ts +69 -0
  319. package/src/types.ts +9 -0
  320. package/templates/thermo-quality-review/README.md +35 -0
  321. package/templates/thermo-quality-review/agent/agent.ts +8 -0
  322. package/templates/thermo-quality-review/agent/channels/github.ts +42 -0
  323. package/templates/thermo-quality-review/agent/instructions.md +43 -0
  324. package/templates/thermo-quality-review/agent/tools/post_findings.ts +70 -0
  325. package/templates/thermo-quality-review/evals/evals.config.ts +5 -0
  326. package/templates/thermo-quality-review/evals/review.eval.ts +62 -0
  327. package/templates/thermo-quality-review/package.json +18 -0
  328. package/templates/thermo-quality-review/tsconfig.json +12 -0
  329. package/templates/thermo-review/README.md +35 -0
  330. package/templates/thermo-review/agent/agent.ts +8 -0
  331. package/templates/thermo-review/agent/channels/github.ts +42 -0
  332. package/templates/thermo-review/agent/instructions.md +40 -0
  333. package/templates/thermo-review/agent/tools/post_findings.ts +70 -0
  334. package/templates/thermo-review/evals/evals.config.ts +5 -0
  335. package/templates/thermo-review/evals/review.eval.ts +53 -0
  336. package/templates/thermo-review/package.json +18 -0
  337. package/templates/thermo-review/tsconfig.json +12 -0
  338. package/dist/docs/assets/building-with-agents.md.CEGVXkmO.js +0 -13
  339. package/dist/docs/assets/building-with-agents.md.CEGVXkmO.lean.js +0 -1
  340. package/dist/docs/assets/chunks/@localSearchIndexroot.DtXk1hy-.js +0 -1
  341. package/dist/docs/assets/chunks/channel.Bkv1N-gK.js +0 -1
  342. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CZDco1o8.js +0 -1
  343. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CZDco1o8.js +0 -1
  344. package/dist/docs/assets/chunks/clone.YSt_40_s.js +0 -1
  345. package/dist/docs/assets/chunks/framework.dypDpWZ3.js +0 -19
  346. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.C4CLm481.js +0 -1
  347. package/dist/docs/assets/chunks/wardley-RL74JXVD.g5efOWmT.js +0 -162
  348. package/dist/docs/assets/deployment.md.Dm4Qo3hp.js +0 -51
  349. package/dist/docs/assets/deployment.md.Dm4Qo3hp.lean.js +0 -1
  350. package/dist/docs/assets/evals.md.BLDRt5LH.js +0 -211
  351. package/dist/docs/assets/evals.md.BLDRt5LH.lean.js +0 -1
  352. package/dist/docs/assets/guides_agent-to-agent.md.BI0xclmy.js +0 -14
  353. package/dist/docs/assets/guides_agent-to-agent.md.BI0xclmy.lean.js +0 -1
  354. package/dist/docs/assets/guides_bitbucket.md.CTpCl__f.js +0 -10
  355. package/dist/docs/assets/guides_bitbucket.md.CTpCl__f.lean.js +0 -1
  356. package/dist/docs/assets/guides_cloud-agents.md.lSE_l7lH.js +0 -9
  357. package/dist/docs/assets/guides_cloud-agents.md.lSE_l7lH.lean.js +0 -1
  358. package/dist/docs/assets/guides_convert-automation.md.Ck6Cr68A.js +0 -12
  359. package/dist/docs/assets/guides_convert-automation.md.Ck6Cr68A.lean.js +0 -1
  360. package/dist/docs/assets/guides_github.md.D6ER29dG.js +0 -64
  361. package/dist/docs/assets/guides_github.md.D6ER29dG.lean.js +0 -1
  362. package/dist/docs/assets/guides_gitlab.md.P-TjBnS5.js +0 -14
  363. package/dist/docs/assets/guides_gitlab.md.P-TjBnS5.lean.js +0 -1
  364. package/dist/docs/assets/guides_grokbot-agents.md.WBZIOvkz.js +0 -9
  365. package/dist/docs/assets/guides_grokbot-agents.md.WBZIOvkz.lean.js +0 -1
  366. package/dist/docs/assets/guides_improve.md.BKaDuKKK.js +0 -14
  367. package/dist/docs/assets/guides_improve.md.BKaDuKKK.lean.js +0 -1
  368. package/dist/docs/assets/guides_mcp-oauth.md.DMNMpXtO.js +0 -28
  369. package/dist/docs/assets/guides_mcp-oauth.md.DMNMpXtO.lean.js +0 -1
  370. package/dist/docs/assets/guides_opentelemetry.md._CRfDyzH.js +0 -26
  371. package/dist/docs/assets/guides_opentelemetry.md._CRfDyzH.lean.js +0 -1
  372. package/dist/docs/assets/guides_slack.md.DdT8rmsj.js +0 -46
  373. package/dist/docs/assets/guides_slack.md.DdT8rmsj.lean.js +0 -1
  374. package/dist/docs/assets/guides_webhooks.md.aQW10HRe.js +0 -225
  375. package/dist/docs/assets/guides_webhooks.md.aQW10HRe.lean.js +0 -1
  376. package/dist/docs/assets/hillclimbing.md.Dq4kkVIL.js +0 -1
  377. package/dist/docs/assets/hillclimbing.md.Dq4kkVIL.lean.js +0 -1
  378. package/dist/docs/assets/reference_extensions.md.wlFD3cUR.js +0 -62
  379. package/dist/docs/assets/reference_extensions.md.wlFD3cUR.lean.js +0 -1
  380. package/dist/docs/assets/troubleshooting.md.BcgNoYtJ.js +0 -1
  381. package/dist/docs/assets/troubleshooting.md.BcgNoYtJ.lean.js +0 -1
  382. package/dist/playground/assets/index-BLlKgZtI.css +0 -1
  383. package/dist/playground/assets/index-CDS5p9sR.js +0 -67
@@ -1,464 +1,233 @@
1
- # Webhooks and custom channels
1
+ # Webhook agents
2
2
 
3
- A custom channel gives the agent its own HTTP surface. You get routes
4
- with validated payloads, sessions keyed to something in your domain (a
5
- thread, a ticket, a PR), and replies delivered back to the caller. The
6
- [Slack](/docs/guides/slack.md) and [GitHub](/docs/guides/github.md) packs build on this
7
- mechanism. The [GitLab](/docs/guides/gitlab.md) and [Bitbucket](/docs/guides/bitbucket.md) packs
8
- use it too. This page is the mechanism itself.
3
+ A custom channel turns an event from another system into an agent
4
+ conversation, then sends the result back to the system that started it.
5
+ Use one when the built-in [HTTP API](/docs/reference/http-api.md) does not
6
+ match the provider's payload, conversation key, or reply path.
9
7
 
10
- ## What you already have
8
+ Author `agent/channels/<id>.ts`. Its routes mount under
9
+ `/<slug>/v1/channels/<id>`.
11
10
 
12
- The built-in HTTP channel is always mounted (under `/<slug>` in the
13
- default multi-agent layout). `POST /v1/session` starts a conversation,
14
- `POST /v1/session/:id` follows up, and `GET /v1/session/:id/stream`
15
- streams NDJSON events, plus sessions, approvals, and tool routes. See
16
- the [HTTP API reference](/docs/reference/http-api.md).
11
+ ## Receive a webhook and send the answer back
17
12
 
18
- Write a custom channel when that shape doesn't fit: a webhook with its
19
- own payload contract, a surface that keys sessions by a domain id, or a
20
- flow that does host-side work before (or instead of) a model turn.
21
-
22
- ## Define a channel
23
-
24
- Author `agent/channels/<id>.ts` with `defineChannel`. The filename is
25
- the channel id, and routes mount under `/v1/channels/<id>`:
13
+ When a ticket system sends a new message, this endpoint responds with
14
+ `202 Accepted` right away. The agent keeps working after the HTTP
15
+ request ends, and its completed answer appears as a comment on the
16
+ ticket.
26
17
 
27
18
  ```ts
19
+ // agent/channels/tickets.ts
28
20
  import { defineChannel, POST } from "@cursor/july/channels";
29
21
  import { z } from "zod";
22
+ import { postTicketComment } from "../lib/tickets.js";
30
23
 
31
- export default defineChannel({
24
+ type TicketState = {
25
+ ticketId: string;
26
+ };
27
+
28
+ export default defineChannel<TicketState>({
29
+ state: { ticketId: "" },
32
30
  routes: [
33
- POST("/message", {
34
- description: "Enqueue a chat turn on this channel",
31
+ POST("/ticket", {
32
+ description: "Answer a new ticket message",
35
33
  bodySchema: z.object({
34
+ ticketId: z.string(),
36
35
  message: z.string(),
37
- thread: z.string().optional(),
38
36
  }),
39
- handler: async (_req, { send, body }) => {
40
- const session = await send(body.message, {
41
- // stable key: same thread → same durable session
42
- continuationToken: body.thread,
43
- });
44
- return Response.json({ sessionId: session.id });
37
+ handler: async (_request, { send, waitUntil, body }) => {
38
+ waitUntil(
39
+ send(body.message, {
40
+ state: { ticketId: body.ticketId },
41
+ title: `Ticket ${body.ticketId}`,
42
+ })
43
+ );
44
+ return Response.json({ accepted: true }, { status: 202 });
45
45
  },
46
46
  }),
47
47
  ],
48
48
  events: {
49
- "message.completed"(event, channel, ctx) {
50
- // deliver the reply back to the surface that owns this channel:
51
- // post to a webhook, reply in a thread, update a ticket, …
49
+ async "message.completed"(event, channel) {
50
+ if (event.data.finishReason === "tool_call" || event.data.text === "") {
51
+ return;
52
+ }
53
+ await postTicketComment(channel.state.ticketId, event.data.text);
52
54
  },
53
55
  },
54
56
  });
55
57
  ```
56
58
 
57
- ```bash
58
- curl -X POST http://127.0.0.1:3000/<slug>/v1/channels/<id>/message \
59
- -H 'content-type: application/json' \
60
- -d '{"message":"hello","thread":"ticket-42"}'
61
- ```
62
-
63
- ## Schemas are Zod, and required
59
+ `postTicketComment` is a small wrapper around the ticket provider's
60
+ SDK. Keeping that write in the event handler means the webhook request
61
+ does not stay open while the model works.
64
62
 
65
- `GET` routes require a Zod `querySchema`. `POST`, `PUT`, and `PATCH`
66
- require a Zod `bodySchema`. Compile-time checks enforce this, so plain
67
- JSON Schema objects won't type-check. Use `z.object({})` or
68
- `z.unknown()` when a surface is intentionally open. The host validates
69
- before your handler runs, handlers receive typed `args.body` and
70
- `args.query`, and empty POST bodies are coerced to `{}` first.
63
+ ## Keep one conversation per ticket
71
64
 
72
- Declared schemas also feed `GET /v1/info`, which adds two things to the
73
- playground: a **Try** button on every route, and matching **slash
74
- commands** in the composer (a channel `drive` route becomes `/drive …`).
65
+ Without a conversation key, every delivery creates a new session. Add
66
+ the ticket ID as the `continuationToken` so the opening message and all
67
+ later comments resume the same conversation, while a different ticket
68
+ starts its own.
75
69
 
76
- ## What a handler receives
77
-
78
- Handlers get the Fetch `Request` plus an args object:
79
-
80
- | Helper | What it does |
81
- | --- | --- |
82
- | `send(message, options?)` | Run a model turn on this channel. `continuationToken` keys the durable session; options can seed `workspaceFiles`, attach `cloud` repos, or override `auth`. |
83
- | `getSession(sessionId)` | Look up an existing session |
84
- | `receive(channel, input)` | Hand off to another channel (schedules use this) |
85
- | `callTool(name, input, opts?)` | Run an authored server tool with no model turn ([Tools](/docs/reference/tools.md#call-a-tool-without-a-model-turn)) |
86
- | `body`, `query`, `params` | Validated payloads and path params |
87
- | `auth` | The `AuthContext` the route's auth chain resolved |
88
- | `requestIp` | The TCP peer address |
89
- | `host` | Shared host services: `host.mcp`, `host.github`, `host.slack`, `host.reminders` |
90
- | `waitUntil(promise)` | Background work that outlives the response |
70
+ ```ts
71
+ waitUntil(
72
+ send(body.message, {
73
+ continuationToken: `ticket:${body.ticketId}`,
74
+ state: { ticketId: body.ticketId },
75
+ title: `Ticket ${body.ticketId}`,
76
+ })
77
+ );
78
+ ```
91
79
 
92
- Channel `state` declares the starting per-session adapter state. It
93
- persists across events, and event handlers receive it on
94
- `channel.state`.
80
+ The channel owns this key. Callers only need to send the domain ID they
81
+ already know.
95
82
 
96
- ## Respond fast, work in the background
83
+ ## Prepare evidence before the turn
97
84
 
98
- Webhook senders time out quickly. GitHub gives you about ten seconds.
99
- For slow work, ACK immediately and continue in the background:
85
+ Webhook payloads often contain little more than an object ID. This
86
+ handler fetches the full ticket through a deterministic tool and writes
87
+ the result to `ticket.json`, so the model begins with a stable snapshot
88
+ instead of spending the turn looking for context.
100
89
 
101
90
  ```ts
102
- handler: async (_req, { send, waitUntil, body }) => {
91
+ handler: async (_request, { callTool, send, waitUntil, body }) => {
92
+ const prepared = await callTool("prepare_ticket", {
93
+ ticketId: body.ticketId,
94
+ });
95
+ if (prepared.isError) {
96
+ return Response.json(
97
+ { error: prepared.errorMessage ?? "Could not prepare ticket" },
98
+ { status: 502 }
99
+ );
100
+ }
101
+
103
102
  waitUntil(
104
- send(`Process incoming report: ${body.url}`, {
105
- continuationToken: `report:${body.id}`,
103
+ send("Read ticket.json, then draft the reply.", {
104
+ continuationToken: `ticket:${body.ticketId}`,
105
+ state: { ticketId: body.ticketId },
106
+ workspaceFiles: {
107
+ "ticket.json": JSON.stringify(prepared.result, null, 2) ?? "null",
108
+ },
106
109
  })
107
110
  );
108
111
  return Response.json({ accepted: true }, { status: 202 });
109
112
  },
110
113
  ```
111
114
 
112
- ## Prepare on the host, then hand off
115
+ The same `message.completed` handler from the first example delivers
116
+ the answer back to the ticket.
113
117
 
114
- The strongest channel pattern: do the deterministic setup in the
115
- handler, then hand the model prepared evidence. Fetch the PR with
116
- `callTool`, seed the files it needs, and make the prompt about judgment
117
- rather than about finding things:
118
+ ## Routes receive, events deliver
118
119
 
119
- ```ts
120
- handler: async (_req, { callTool, send, body }) => {
121
- const prep = await callTool("prepare_pr", { pr: body.pr });
122
- if (prep.isError) {
123
- return Response.json({ ok: false, error: prep.result }, { status: 502 });
124
- }
125
- const session = await send("Review the prepared PR under pr/.", {
126
- continuationToken: `pr:${body.pr}`,
127
- });
128
- return Response.json({ sessionId: session.id });
129
- },
130
- ```
131
-
132
- This host-prep shape is the change with the largest effect on latency
133
- and quality. [Hillclimbing](/docs/hillclimbing.md) lists it first.
134
-
135
- ## Deliver replies back out
136
-
137
- The `events` map subscribes the channel to stream events for the
138
- sessions it owns. Typical wiring: `message.completed` posts the
139
- assistant text back to the caller's surface, and `turn.failed` posts an
140
- error notice. The full vocabulary is in
141
- [Sessions and streaming](/docs/reference/sessions.md#which-events-can-i-stream).
142
-
143
- ## Auth: loopback by default, on purpose
120
+ Routes own inbound HTTP. A route validates the request, decides whether
121
+ to start or resume a turn, and responds to the caller. The channel's
122
+ `events` handlers receive session events later, which is where you
123
+ deliver the model's answer or report a failure to the originating
124
+ system.
144
125
 
145
- Every route runs an auth-policy chain (the channel's `auth` array). The
146
- default is `[localDevStrict()]`: direct loopback callers only. Requests
147
- carrying proxy-forwarding headers (`X-Forwarded-For`, `X-Real-IP`,
148
- `Forwarded`, `X-Forwarded-Host`) are rejected, and a loopback `Host`
149
- header is required. So a tunnel, a same-host reverse proxy, or a
150
- DNS-rebinding page can't silently re-expose the route.
151
-
152
- Before real traffic, author auth explicitly:
153
-
154
- ```ts
155
- import { bearerAuth, defineChannel, localDevStrict } from "@cursor/july/channels";
156
-
157
- export default defineChannel({
158
- auth: [localDevStrict(), bearerAuth(process.env.WEBHOOK_TOKEN ?? "")],
159
- routes: [/* … */],
160
- });
161
- ```
126
+ ## Validate payloads with Zod
162
127
 
163
- The built-in policies are `localDevStrict()` (the default),
164
- `localDev()`, `loopbackOnly()`, `bearerAuth(tokenOrVerify)`, and
165
- `allowAll()`, and `publicEndpoint()`. Any
166
- `(request, info) => AuthContext | null` function composes with them.
128
+ `POST`, `PUT`, and `PATCH` routes require a Zod `bodySchema`; `GET`
129
+ requires a `querySchema`. Validation runs before the handler, and the
130
+ parsed value arrives as typed `body` or `query`. Use `z.unknown()` when
131
+ the provider controls a variable payload and your own parser will
132
+ narrow it.
167
133
 
168
- The details live in
169
- [Channels](/docs/reference/channels.md#auth-policies).
134
+ The route description and schema also appear in `GET /v1/info`. The
135
+ playground uses them to add a **Try** action and a matching slash
136
+ command, so you can exercise the same handler without building a
137
+ separate test UI.
170
138
 
171
- Server-level flags interact with channel auth. `--bearer-token <secret>`
172
- swaps the default for `bearerAuth` on every channel that doesn't author
173
- its own chain, and `--allow-anonymous` swaps it for `allowAll()`
174
- (trusted networks only). Authored `auth` arrays always win over both.
139
+ ## Use handler context
175
140
 
176
- ## Receive signed webhooks on managed hosting
141
+ The handler context keeps deterministic setup and model work in one
142
+ route:
177
143
 
178
- Cursor-managed deployments expose a stable alias URL. External callers
179
- normally send `X-Agent-Alias-Token` on every request. Webhook providers
180
- often cannot set it.
144
+ - `send` starts or resumes the agent conversation.
181
145
 
182
- Add `publicEndpoint()` to a custom channel that verifies its own provider
183
- signature. Only that channel path skips the alias token. Session and tool
184
- routes stay private. See [Deployment](/docs/deployment.md#use-the-hosted-agent).
146
+ - `callTool` runs an authored server tool without starting a model
147
+ turn.
185
148
 
186
- ## Example: Linear as the control plane
149
+ - `waitUntil` keeps background work alive after the HTTP response. Await
150
+ `send` when the caller needs the session handle, then call
151
+ `session.waitForCompletion()` if it also needs the turn outcome.
187
152
 
188
- Everything above composes into a working ticket-driven agent. This
189
- example wires Linear to the agent: new issues and comments start or
190
- resume sessions, and replies land back on the issue as comments. The
191
- same shape works for any tracker with signed webhooks.
153
+ - `host` provides authenticated services for API calls made by channel
154
+ code.
192
155
 
193
- Create the webhook in Linear under Settings → API "New webhook",
194
- pointed at `https://<your-host>/<slug>/v1/channels/linear`, and copy
195
- the signing secret. Linear requires a public HTTPS URL, so use a
196
- tunnel during local development or test with signed fixtures (below).
197
- Set three environment variables:
156
+ The full handler API lives in the
157
+ [Channels reference](/docs/reference/channels.md#handler-arguments).
198
158
 
199
- ```bash
200
- LINEAR_WEBHOOK_SECRET=lin_wh_... # the webhook's signing secret
201
- LINEAR_API_KEY=lin_api_... # posts replies as comments
202
- LINEAR_AGENT_USER_ID=... # the API key's user: query { viewer { id } }
203
- ```
159
+ ## Protect public webhooks
204
160
 
205
- `LINEAR_AGENT_USER_ID` matters: replies posted with the API key
206
- trigger the Comment webhook again, so the channel must recognize and
207
- skip its own comments. Without the guard, every reply starts another
208
- turn.
161
+ Custom routes accept direct loopback requests by default. They reject
162
+ forwarded requests, so a tunnel or reverse proxy does not silently turn
163
+ a local development endpoint into a public one.
209
164
 
210
- Author `agent/channels/linear.ts`:
165
+ Before accepting remote traffic, choose an explicit boundary.
166
+ `bearerAuth()` works when the sender can attach an authorization header.
167
+ On managed hosting, webhook providers often cannot attach the agent
168
+ alias token, so `publicEndpoint()` lets that custom channel bypass it.
169
+ That opens the route to every caller; verify the provider signature
170
+ before starting a turn or calling a tool.
211
171
 
212
172
  ```ts
213
- import { Buffer } from "node:buffer";
214
- import { createHmac, timingSafeEqual } from "node:crypto";
215
173
  import { defineChannel, POST, publicEndpoint } from "@cursor/july/channels";
216
174
  import { z } from "zod";
217
-
218
- const secret = process.env.LINEAR_WEBHOOK_SECRET ?? "";
219
- const apiKey = process.env.LINEAR_API_KEY ?? "";
220
- const agentUserId = process.env.LINEAR_AGENT_USER_ID ?? "";
221
-
222
- interface LinearWebhook {
223
- action: string;
224
- type: string;
225
- url?: string;
226
- webhookTimestamp: number;
227
- data: {
228
- id: string;
229
- title?: string;
230
- description?: string;
231
- body?: string;
232
- issueId?: string;
233
- userId?: string;
234
- };
235
- }
236
-
237
- // Linear signs the raw body: hex HMAC-SHA256 in `Linear-Signature`.
238
- function verified(rawBody: string, header: string | null): boolean {
239
- if (secret === "" || header === null) {
240
- return false;
241
- }
242
- const expected = createHmac("sha256", secret).update(rawBody).digest();
243
- const received = Buffer.from(header, "hex");
244
- return (
245
- received.length === expected.length && timingSafeEqual(received, expected)
246
- );
247
- }
248
-
249
- async function postComment(issueId: string, body: string): Promise<void> {
250
- const response = await fetch("https://api.linear.app/graphql", {
251
- method: "POST",
252
- headers: { "content-type": "application/json", authorization: apiKey },
253
- body: JSON.stringify({
254
- query:
255
- "mutation($input: CommentCreateInput!) { commentCreate(input: $input) { success } }",
256
- variables: { input: { issueId, body } },
257
- }),
258
- });
259
- if (!response.ok) {
260
- throw new Error(`commentCreate failed: ${response.status}`);
261
- }
262
- }
263
-
264
- function issueIdFromToken(token: string | null): string | null {
265
- if (token === null || !token.startsWith("linear:")) {
266
- return null;
267
- }
268
- return token.slice("linear:".length);
269
- }
175
+ import { verifyProviderSignature } from "../lib/tickets.js";
270
176
 
271
177
  export default defineChannel({
272
178
  auth: [publicEndpoint()],
273
179
  routes: [
274
180
  POST("/", {
275
- description: "Linear webhook ingress",
276
- // The payload shape varies by `Linear-Event`; parse after verifying.
181
+ description: "Signed ticket webhook",
277
182
  bodySchema: z.unknown(),
278
- handler: async (request, { send, waitUntil }) => {
183
+ handler: async request => {
279
184
  const rawBody = await request.text();
280
- if (!verified(rawBody, request.headers.get("linear-signature"))) {
281
- return Response.json({ ok: false }, { status: 401 });
282
- }
283
- const event = JSON.parse(rawBody) as LinearWebhook;
284
- // Reject stale deliveries to guard against replay.
285
- if (Math.abs(Date.now() - event.webhookTimestamp) > 60_000) {
185
+ const signature = request.headers.get("x-provider-signature");
186
+ if (!verifyProviderSignature(rawBody, signature)) {
286
187
  return Response.json({ ok: false }, { status: 401 });
287
188
  }
288
- // Skip the agent's own comments so replies don't re-trigger it.
289
- if (event.type === "Comment" && event.data.userId === agentUserId) {
290
- return Response.json({ ok: true });
291
- }
292
-
293
- // New issue → new session. New comment → follow-up on the same
294
- // session, keyed by issue id through the continuation token.
295
- let issueId: string | undefined;
296
- let message: string | undefined;
297
- if (event.type === "Issue" && event.action === "create") {
298
- issueId = event.data.id;
299
- message = `New Linear issue: ${event.data.title}\n\n${
300
- event.data.description ?? ""
301
- }\n${event.url ?? ""}`;
302
- } else if (event.type === "Comment" && event.action === "create") {
303
- issueId = event.data.issueId;
304
- message = event.data.body;
305
- }
306
- if (issueId === undefined || message === undefined) {
307
- return Response.json({ ok: true });
308
- }
309
189
 
310
- // Linear retries on any non-200 and times out after five
311
- // seconds: ACK now, run the turn in the background.
312
- waitUntil(send(message, { continuationToken: `linear:${issueId}` }));
190
+ // Parse and dispatch only after the signature passes.
313
191
  return Response.json({ ok: true });
314
192
  },
315
193
  }),
316
194
  ],
317
- events: {
318
- async "message.completed"(event, channel) {
319
- if (event.data.finishReason === "tool_call" || event.data.text === "") {
320
- return;
321
- }
322
- const issueId = issueIdFromToken(channel.continuationToken);
323
- if (issueId !== null) {
324
- await postComment(issueId, event.data.text);
325
- }
326
- },
327
- async "turn.failed"(event, channel) {
328
- const issueId = issueIdFromToken(channel.continuationToken);
329
- if (issueId !== null) {
330
- await postComment(issueId, `Turn failed: ${event.data.message}`);
331
- }
332
- },
333
- },
334
195
  });
335
196
  ```
336
197
 
337
- The channel handles ingress and reply delivery deterministically. To
338
- let the model read and update Linear during the turn (search related
339
- issues, change state, assign), add the Linear MCP connection alongside
340
- it:
341
-
342
- ```ts
343
- // agent/mcp-connections/linear.ts
344
- import { defineConnection } from "@cursor/july/connections";
345
-
346
- // Uses the signed-in Cursor account's Linear connector.
347
- export default defineConnection({ cursorAccount: true, servers: ["Linear"] });
348
- ```
349
-
350
- See [MCP connections](/docs/reference/connections.md) for the direct
351
- `https://mcp.linear.app/mcp` form when the host isn't signed in to
352
- Cursor.
353
-
354
- ### Production Linear agents: expiring OAuth tokens
198
+ `publicEndpoint()` only opens this channel's routes. The built-in
199
+ session and tool APIs stay private. See
200
+ [Auth policies](/docs/reference/channels.md#auth-policies) for bearer
201
+ tokens and the complete policy reference.
355
202
 
356
- A plain API key fits a personal integration. A production Linear agent
357
- is an OAuth application: installing it in a workspace mints an access
358
- token with an expiry plus a refresh token. The serve host can be
359
- replaced at any time, so the pair can't live in process memory.
360
- Persist it in `host.kv` instead.
361
- Route handlers receive `host` in their args, and event handlers get the
362
- same services on `ctx`.
203
+ ## Test locally
363
204
 
364
- Two prerequisites:
365
-
366
- - Keep the OAuth client id and client secret in
367
- [deployment secrets](/docs/deployment.md). They're static, so
368
- deploy-time env vars fit them.
369
- - Back kv with durable storage. On Cursor-managed hosting, use
370
- `cursorHostedStorage` in `agent/storage.ts`. Without it, kv falls back
371
- to local disk and a host replacement drops the tokens.
372
-
373
- Save the pair when the install flow completes, then refresh on demand:
374
-
375
- ```ts
376
- import type { HostKvApi } from "@cursor/july/kv";
377
-
378
- interface LinearTokens {
379
- accessToken: string;
380
- refreshToken: string;
381
- expiresAtMs: number;
382
- }
383
-
384
- const TOKENS_KEY = "linear/oauth-tokens";
385
-
386
- export async function linearAccessToken(kv: HostKvApi): Promise<string> {
387
- const tokens = (await kv.get(TOKENS_KEY)) as LinearTokens | undefined;
388
- if (tokens === undefined) {
389
- throw new Error("No Linear tokens stored. Complete the install flow first.");
390
- }
391
- if (Date.now() < tokens.expiresAtMs - 60_000) {
392
- return tokens.accessToken;
393
- }
394
- const response = await fetch("https://api.linear.app/oauth/token", {
395
- method: "POST",
396
- headers: { "content-type": "application/x-www-form-urlencoded" },
397
- body: new URLSearchParams({
398
- grant_type: "refresh_token",
399
- refresh_token: tokens.refreshToken,
400
- client_id: process.env.LINEAR_CLIENT_ID ?? "",
401
- client_secret: process.env.LINEAR_CLIENT_SECRET ?? "",
402
- }),
403
- });
404
- if (!response.ok) {
405
- throw new Error(`Linear token refresh failed: ${response.status}`);
406
- }
407
- const next = (await response.json()) as {
408
- access_token: string;
409
- refresh_token?: string;
410
- expires_in: number;
411
- };
412
- const rotated: LinearTokens = {
413
- accessToken: next.access_token,
414
- refreshToken: next.refresh_token ?? tokens.refreshToken,
415
- expiresAtMs: Date.now() + next.expires_in * 1000,
416
- };
417
- await kv.put(TOKENS_KEY, rotated);
418
- return rotated.accessToken;
419
- }
420
- ```
421
-
422
- Then authorize GraphQL calls with `Bearer ${await
423
- linearAccessToken(host.kv)}` in place of the static `apiKey` above.
424
- Writes to `host.kv` await the durable sink and propagate errors, so a
425
- failed save surfaces instead of silently losing the rotated refresh
426
- token.
427
-
428
- To test without a public URL, save a payload from the webhook's
429
- delivery log (or the sample in
430
- [Linear's webhook docs](https://linear.app/developers/webhooks)) under
431
- `fixtures/`, refresh its `webhookTimestamp`, and sign it yourself:
205
+ Run the agent in development mode, then replay the same payload the
206
+ provider will send. The response should return immediately, and the
207
+ resulting session should appear in the playground while the reply is
208
+ delivered.
432
209
 
433
210
  ```bash
434
- SIG=$(node -e 'const {createHmac}=require("node:crypto");const fs=require("node:fs");
435
- process.stdout.write(createHmac("sha256",process.env.LINEAR_WEBHOOK_SECRET)
436
- .update(fs.readFileSync("fixtures/issue-create.json")).digest("hex"))')
437
- curl -X POST http://127.0.0.1:3000/<slug>/v1/channels/linear/ \
438
- -H 'content-type: application/json' -H "linear-signature: $SIG" \
439
- --data-binary @fixtures/issue-create.json
440
- ```
441
-
442
- ## Test a channel
211
+ agent-sdk serve --dir . --dev
443
212
 
444
- Start with curl and saved payloads under `fixtures/`. The playground's
445
- **Try** modal covers manual probes. It remembers your last body per
446
- endpoint, has Copy curl, and opens the created session on a successful
447
- Try. For regression coverage, drive the same behavior through an eval,
448
- or keep channel logic deterministic in `agent/lib/` and unit-test it
449
- there. When something looks wrong, inspect the session event stream.
450
- The stream is the record of what happened.
451
-
452
- For GitHub specifically, don't hand-roll fixtures.
453
- `agent-sdk github replay` synthesizes real-shaped, signed payloads
454
- from any PR you can read. See the [GitHub guide](/docs/guides/github.md).
455
-
456
- ## What's next
457
-
458
- Continue with these pages:
213
+ curl -sS -X POST \
214
+ http://127.0.0.1:3000/<slug>/v1/channels/tickets/ticket \
215
+ -H 'content-type: application/json' \
216
+ -d '{"ticketId":"ENG-142","message":"CSV export returns 500"}'
217
+ ```
459
218
 
460
- - [Channels reference](/docs/reference/channels.md): the full authoring API
461
- - [GitHub](/docs/guides/github.md), [GitLab](/docs/guides/gitlab.md),
462
- [Bitbucket](/docs/guides/bitbucket.md), and [Slack](/docs/guides/slack.md): the packaged channels
463
- - [Sessions and streaming](/docs/reference/sessions.md): events your
464
- channel can subscribe to
219
+ Keep representative payloads under `fixtures/` and pass them with
220
+ `--data-binary @fixtures/<event>.json`. You can also open the route's
221
+ **Try** action in the playground for manual probes.
222
+
223
+ ## Related
224
+
225
+ - [Channels reference](/docs/reference/channels.md): route methods,
226
+ handler arguments, events, state, and auth policies
227
+ - [Triage Linear or Jira issues](/docs/templates/triage.md): a complete
228
+ signed tracker webhook with reply delivery
229
+ - [HTTP API](/docs/reference/http-api.md): built-in session, follow-up,
230
+ stream, and tool routes
231
+ - [Deployment](/docs/deployment.md#use-the-hosted-agent): stable hosted
232
+ URLs and alias-token behavior
233
+ - [Evals](/docs/evals.md): turn saved payloads into regression fixtures
@@ -1 +1 @@
1
- {"building-with-agents.md":"CEGVXkmO","deployment.md":"Dm4Qo3hp","evals.md":"BLDRt5LH","guides_agent-to-agent.md":"BI0xclmy","guides_bitbucket.md":"CTpCl__f","guides_cloud-agents.md":"lSE_l7lH","guides_convert-automation.md":"Ck6Cr68A","guides_github.md":"D6ER29dG","guides_gitlab.md":"P-TjBnS5","guides_grokbot-agents.md":"WBZIOvkz","guides_improve.md":"BKaDuKKK","guides_mcp-oauth.md":"DMNMpXtO","guides_opentelemetry.md":"_CRfDyzH","guides_slack.md":"DdT8rmsj","guides_webhooks.md":"aQW10HRe","hillclimbing.md":"Dq4kkVIL","index.md":"BFVyY2KT","quickstart.md":"D3MjSZN-","reference_agent-config.md":"CfVA-LZJ","reference_artifacts.md":"Vf7qyIZ-","reference_channels.md":"icqLKcTc","reference_cli.md":"B2dBL6L8","reference_connections.md":"Cb3U_c8n","reference_extensions.md":"wlFD3cUR","reference_hooks.md":"CZuynAxj","reference_http-api.md":"DTKcYE6L","reference_instructions.md":"D7gkckK-","reference_playground.md":"D2YExv5K","reference_project-layout.md":"DPxbUJyt","reference_prompt.md":"BQ5uAv1F","reference_schedules.md":"BasfZWO-","reference_sessions.md":"YKvIsWAx","reference_skills.md":"rNgpsGd0","reference_subagents.md":"e5qitjJt","reference_tools.md":"BdCO2aHZ","templates_agentic-owners.md":"Da_AGDlH","templates_pr-autofixer.md":"DqxocIGh","templates_security-reviewer.md":"Bhnvd8VE","templates_triage.md":"BdBWO9Ic","troubleshooting.md":"BcgNoYtJ"}
1
+ {"building-with-agents.md":"BBCx0AUo","deployment.md":"D2jQZuFx","evals.md":"BYvfZ-PO","guides_agent-to-agent.md":"8oDTfu-E","guides_bitbucket.md":"mpevW-VP","guides_cloud-agents.md":"Cp1O3u-X","guides_convert-automation.md":"CqEyfP6Y","guides_github.md":"BwpBp3ed","guides_gitlab.md":"DaEC3nMk","guides_grokbot-agents.md":"CMhZNdEU","guides_improve.md":"Bnp4F99w","guides_mcp-oauth.md":"bSFakfCY","guides_opentelemetry.md":"BKDxQmmd","guides_slack.md":"Bo96y42E","guides_webhooks.md":"1A72_VEE","hillclimbing.md":"D4E1o5Sa","index.md":"C-t81M5J","quickstart.md":"DAvVhuuU","reference_agent-config.md":"DGPyw7ms","reference_artifacts.md":"Bu_4HmsD","reference_channels.md":"nFWbzAic","reference_cli.md":"DLWDz9ij","reference_connections.md":"CmyrlXfY","reference_evals.md":"DNJzM_yf","reference_extensions.md":"Ceq-qT8d","reference_hooks.md":"B7uzNENk","reference_http-api.md":"CduHavZ2","reference_instructions.md":"CU1My5My","reference_playground.md":"Ch2d0Iqi","reference_project-layout.md":"BGhgpy9V","reference_prompt.md":"Ccp0R53H","reference_schedules.md":"B2Nm6FaD","reference_sessions.md":"1_6Vyv7x","reference_skills.md":"DjQkRefx","reference_subagents.md":"BHsSMMyO","reference_tools.md":"BYzUTeVA","templates_agentic-owners.md":"9M575F5C","templates_pr-autofixer.md":"ws0DDXDy","templates_security-reviewer.md":"KEFYXzfK","templates_thermo-quality-review.md":"VNJ_mohX","templates_thermo-review.md":"Hi3zWOkP","templates_triage.md":"CVGe_FG6","troubleshooting.md":"mnfFG2Em"}