@cursor/july 0.1.107 → 0.1.109

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 (523) hide show
  1. package/AGENTS.md +2 -6
  2. package/README.md +13 -11
  3. package/dist/bin/agent-serve.js +30 -8
  4. package/dist/channels/bitbucket/api.d.ts +41 -0
  5. package/dist/channels/bitbucket/api.d.ts.map +1 -1
  6. package/dist/channels/bitbucket/api.js +260 -0
  7. package/dist/channels/bitbucket/binding.d.ts +4 -0
  8. package/dist/channels/bitbucket/binding.d.ts.map +1 -1
  9. package/dist/channels/bitbucket/binding.js +16 -0
  10. package/dist/channels/bitbucket/index.d.ts +1 -1
  11. package/dist/channels/bitbucket/index.d.ts.map +1 -1
  12. package/dist/channels/bitbucket/index.js +1 -1
  13. package/dist/channels/github/github-channel.js +8 -5
  14. package/dist/channels/github/types.d.ts +5 -1
  15. package/dist/channels/github/types.d.ts.map +1 -1
  16. package/dist/channels/gitlab/api.d.ts +27 -0
  17. package/dist/channels/gitlab/api.d.ts.map +1 -1
  18. package/dist/channels/gitlab/api.js +88 -0
  19. package/dist/channels/gitlab/binding.d.ts +5 -0
  20. package/dist/channels/gitlab/binding.d.ts.map +1 -1
  21. package/dist/channels/gitlab/binding.js +10 -0
  22. package/dist/channels/gitlab/index.d.ts +1 -1
  23. package/dist/channels/gitlab/index.d.ts.map +1 -1
  24. package/dist/channels/gitlab/index.js +1 -1
  25. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  26. package/dist/channels/origin/origin-channel.js +27 -13
  27. package/dist/channels/origin/types.d.ts +5 -1
  28. package/dist/channels/origin/types.d.ts.map +1 -1
  29. package/dist/channels/slack/dispatch.d.ts +10 -0
  30. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  31. package/dist/channels/slack/dispatch.js +20 -3
  32. package/dist/channels/slack/slack-channel.d.ts +12 -5
  33. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  34. package/dist/channels/slack/slack-channel.js +59 -8
  35. package/dist/channels.d.ts +45 -0
  36. package/dist/channels.d.ts.map +1 -1
  37. package/dist/channels.js +106 -7
  38. package/dist/connections.d.ts +2 -1
  39. package/dist/connections.d.ts.map +1 -1
  40. package/dist/connections.js +2 -1
  41. package/dist/docs/404.html +2 -2
  42. package/dist/docs/assets/{app.CtuckIiL.js → app.Cr-wVbnB.js} +1 -1
  43. package/dist/docs/assets/{building-with-agents.md.CUSWxlP_.js → building-with-agents.md.D0KbSkJn.js} +2 -2
  44. package/dist/docs/assets/{building-with-agents.md.CUSWxlP_.lean.js → building-with-agents.md.D0KbSkJn.lean.js} +1 -1
  45. package/dist/docs/assets/chunks/@localSearchIndexroot.CFVQ4S17.js +1 -0
  46. package/dist/docs/assets/chunks/{VPLocalSearchBox.Bkkhnu8K.js → VPLocalSearchBox.CVQERt56.js} +1 -1
  47. package/dist/docs/assets/chunks/{theme.DhpIe0Pa.js → theme.Dnsd3XOn.js} +2 -2
  48. package/dist/docs/assets/concepts.md.B4o63Gul.js +1 -0
  49. package/dist/docs/assets/{deployment.md.MFPKqsqI.js → deployment.md.JenwuCCB.js} +4 -4
  50. package/dist/docs/assets/{deployment.md.MFPKqsqI.lean.js → deployment.md.JenwuCCB.lean.js} +1 -1
  51. package/dist/docs/assets/evals.md.C7JLjoEP.js +211 -0
  52. package/dist/docs/assets/evals.md.C7JLjoEP.lean.js +1 -0
  53. package/dist/docs/assets/guides_bitbucket.md.DZPzmUjU.js +10 -0
  54. package/dist/docs/assets/guides_bitbucket.md.DZPzmUjU.lean.js +1 -0
  55. package/dist/docs/assets/guides_cloud-agents.md.BsloyHdY.js +9 -0
  56. package/dist/docs/assets/{guides_cloud-agents.md.DS8RIjwx.lean.js → guides_cloud-agents.md.BsloyHdY.lean.js} +1 -1
  57. package/dist/docs/assets/{guides_github.md.c0gdGJ-D.js → guides_github.md.TZaTZlfz.js} +13 -3
  58. package/dist/docs/assets/{guides_github.md.c0gdGJ-D.lean.js → guides_github.md.TZaTZlfz.lean.js} +1 -1
  59. package/dist/docs/assets/guides_gitlab.md.BmqwQfdG.js +14 -0
  60. package/dist/docs/assets/guides_gitlab.md.BmqwQfdG.lean.js +1 -0
  61. package/dist/docs/assets/{guides_grokbot-agents.md.DVqdhBKb.js → guides_grokbot-agents.md.DyV-WArv.js} +1 -1
  62. package/dist/docs/assets/guides_improve.md.BGVk32bK.js +14 -0
  63. package/dist/docs/assets/guides_improve.md.BGVk32bK.lean.js +1 -0
  64. package/dist/docs/assets/{guides_slack.md.9oHPye9o.js → guides_slack.md.D4RVMM4G.js} +3 -3
  65. package/dist/docs/assets/{guides_slack.md.9oHPye9o.lean.js → guides_slack.md.D4RVMM4G.lean.js} +1 -1
  66. package/dist/docs/assets/{guides_webhooks.md.DKdA43Qm.js → guides_webhooks.md.CJK484ex.js} +2 -2
  67. package/dist/docs/assets/{hillclimbing.md.CpTGTCle.js → hillclimbing.md.BOiVo1tf.js} +1 -1
  68. package/dist/docs/assets/index.md.DD9Q2XuJ.js +5 -0
  69. package/dist/docs/assets/{index.md.BW_6tOgR.lean.js → index.md.DD9Q2XuJ.lean.js} +1 -1
  70. package/dist/docs/assets/{reference_agent-config.md.CHNpiyp4.js → reference_agent-config.md.CvoL6pof.js} +1 -1
  71. package/dist/docs/assets/{reference_channels.md.D-qTqwcq.js → reference_channels.md.CAo-iK4j.js} +2 -2
  72. package/dist/docs/assets/{reference_channels.md.D-qTqwcq.lean.js → reference_channels.md.CAo-iK4j.lean.js} +1 -1
  73. package/dist/docs/assets/{reference_cli.md.Dm67hd2D.js → reference_cli.md.Deg7849l.js} +7 -7
  74. package/dist/docs/assets/{reference_cli.md.Dm67hd2D.lean.js → reference_cli.md.Deg7849l.lean.js} +1 -1
  75. package/dist/docs/assets/{reference_connections.md.Di6jJAXF.js → reference_connections.md.BojkC6c5.js} +1 -1
  76. package/dist/docs/assets/{reference_extensions.md.CGmMLblt.js → reference_extensions.md.ZAVUyuEX.js} +3 -3
  77. package/dist/docs/assets/{reference_hooks.md.Ddt5DdgJ.js → reference_hooks.md.BlM_bOg6.js} +3 -3
  78. package/dist/docs/assets/{reference_hooks.md.Ddt5DdgJ.lean.js → reference_hooks.md.BlM_bOg6.lean.js} +1 -1
  79. package/dist/docs/assets/{reference_http-api.md.oySXBO8o.js → reference_http-api.md.BwaCo-VO.js} +1 -1
  80. package/dist/docs/assets/{reference_playground.md.4myJPxrf.js → reference_playground.md.DLnoaczX.js} +1 -1
  81. package/dist/docs/assets/{reference_playground.md.4myJPxrf.lean.js → reference_playground.md.DLnoaczX.lean.js} +1 -1
  82. package/dist/docs/assets/{reference_project-layout.md.DuBu9a96.js → reference_project-layout.md.BEU8MtQV.js} +3 -3
  83. package/dist/docs/assets/{reference_project-layout.md.DuBu9a96.lean.js → reference_project-layout.md.BEU8MtQV.lean.js} +1 -1
  84. package/dist/docs/assets/reference_sessions.md.CyXV1MUw.js +1 -0
  85. package/dist/docs/assets/{scaffolding-agents.md.em43xlY1.js → scaffolding-agents.md.Kctn3OVb.js} +1 -1
  86. package/dist/docs/assets/{skills_create-agent.md.BVoWPcan.js → skills_create-agent.md.Q3h6Je-e.js} +1 -1
  87. package/dist/docs/assets/{skills_debug.md.CDbPhHfg.js → skills_debug.md.CVjCXMFF.js} +1 -1
  88. package/dist/docs/assets/{skills_debug.md.CDbPhHfg.lean.js → skills_debug.md.CVjCXMFF.lean.js} +1 -1
  89. package/dist/docs/assets/skills_deploy.md.CWqi_ZxW.js +35 -0
  90. package/dist/docs/assets/skills_deploy.md.CWqi_ZxW.lean.js +1 -0
  91. package/dist/docs/assets/skills_evals.md.DFxYPErF.js +25 -0
  92. package/dist/docs/assets/skills_evals.md.DFxYPErF.lean.js +1 -0
  93. package/dist/docs/assets/skills_framework-map.md.BxLSOhSY.js +1 -0
  94. package/dist/docs/assets/{skills_framework-map.md.haibFyoB.lean.js → skills_framework-map.md.BxLSOhSY.lean.js} +1 -1
  95. package/dist/docs/assets/{skills_github.md.D0JahM8c.js → skills_github.md.hgFX_oKY.js} +1 -1
  96. package/dist/docs/assets/skills_index.md.DL7EHaQ-.js +1 -0
  97. package/dist/docs/assets/skills_index.md.DL7EHaQ-.lean.js +1 -0
  98. package/dist/docs/assets/{storage.md.BOHeqk2M.js → storage.md.BUrhJ-Zz.js} +4 -4
  99. package/dist/docs/assets/{storage.md.BOHeqk2M.lean.js → storage.md.BUrhJ-Zz.lean.js} +1 -1
  100. package/dist/docs/assets/troubleshooting.md.CYEAO9bM.js +1 -0
  101. package/dist/docs/building-with-agents.html +5 -5
  102. package/dist/docs/building-with-agents.md +3 -2
  103. package/dist/docs/concepts.html +5 -5
  104. package/dist/docs/concepts.md +2 -4
  105. package/dist/docs/deployment.html +7 -7
  106. package/dist/docs/deployment.md +7 -2
  107. package/dist/docs/evals.html +161 -35
  108. package/dist/docs/evals.md +612 -296
  109. package/dist/docs/guides/agent-to-agent.html +4 -4
  110. package/dist/docs/guides/bitbucket.html +36 -0
  111. package/dist/docs/guides/bitbucket.md +84 -0
  112. package/dist/docs/guides/cloud-agents.html +6 -6
  113. package/dist/docs/guides/cloud-agents.md +4 -3
  114. package/dist/docs/guides/convert-automation.html +4 -4
  115. package/dist/docs/guides/github.html +17 -7
  116. package/dist/docs/guides/github.md +33 -1
  117. package/dist/docs/guides/gitlab.html +40 -0
  118. package/dist/docs/guides/gitlab.md +92 -0
  119. package/dist/docs/guides/grokbot-agents.html +6 -6
  120. package/dist/docs/guides/grokbot-agents.md +2 -2
  121. package/dist/docs/guides/human-in-the-loop.html +4 -4
  122. package/dist/docs/guides/improve.html +40 -0
  123. package/dist/docs/guides/improve.md +91 -0
  124. package/dist/docs/guides/mcp-oauth.html +4 -4
  125. package/dist/docs/guides/opentelemetry.html +5 -5
  126. package/dist/docs/guides/slack.html +7 -7
  127. package/dist/docs/guides/slack.md +2 -1
  128. package/dist/docs/guides/webhooks.html +6 -6
  129. package/dist/docs/guides/webhooks.md +4 -2
  130. package/dist/docs/hashmap.json +1 -1
  131. package/dist/docs/hillclimbing.html +6 -6
  132. package/dist/docs/hillclimbing.md +2 -2
  133. package/dist/docs/index.html +6 -6
  134. package/dist/docs/index.md +14 -6
  135. package/dist/docs/llms-full.txt +1274 -814
  136. package/dist/docs/llms.txt +7 -5
  137. package/dist/docs/quickstart.html +4 -4
  138. package/dist/docs/reference/agent-config.html +6 -6
  139. package/dist/docs/reference/agent-config.md +5 -2
  140. package/dist/docs/reference/artifacts.html +4 -4
  141. package/dist/docs/reference/channels.html +6 -6
  142. package/dist/docs/reference/channels.md +16 -3
  143. package/dist/docs/reference/cli.html +11 -11
  144. package/dist/docs/reference/cli.md +24 -15
  145. package/dist/docs/reference/connections.html +6 -6
  146. package/dist/docs/reference/connections.md +2 -1
  147. package/dist/docs/reference/extensions.html +8 -8
  148. package/dist/docs/reference/extensions.md +2 -3
  149. package/dist/docs/reference/hooks.html +7 -7
  150. package/dist/docs/reference/hooks.md +9 -12
  151. package/dist/docs/reference/http-api.html +6 -6
  152. package/dist/docs/reference/http-api.md +2 -3
  153. package/dist/docs/reference/instructions.html +4 -4
  154. package/dist/docs/reference/playground.html +5 -5
  155. package/dist/docs/reference/playground.md +0 -4
  156. package/dist/docs/reference/project-layout.html +7 -7
  157. package/dist/docs/reference/project-layout.md +1 -8
  158. package/dist/docs/reference/prompt.html +4 -4
  159. package/dist/docs/reference/result.html +4 -4
  160. package/dist/docs/reference/schedules.html +4 -4
  161. package/dist/docs/reference/sessions.html +5 -5
  162. package/dist/docs/reference/sessions.md +1 -2
  163. package/dist/docs/reference/skills.html +4 -4
  164. package/dist/docs/reference/subagents.html +4 -4
  165. package/dist/docs/reference/tools.html +4 -4
  166. package/dist/docs/scaffolding-agents.html +5 -5
  167. package/dist/docs/scaffolding-agents.md +2 -1
  168. package/dist/docs/skills/create-agent.html +6 -6
  169. package/dist/docs/skills/create-agent.md +1 -1
  170. package/dist/docs/skills/debug.html +5 -5
  171. package/dist/docs/skills/debug.md +1 -1
  172. package/dist/docs/skills/deploy.html +61 -0
  173. package/dist/docs/skills/deploy.md +161 -0
  174. package/dist/docs/skills/evals.html +8 -8
  175. package/dist/docs/skills/evals.md +44 -6
  176. package/dist/docs/skills/framework-map.html +5 -5
  177. package/dist/docs/skills/framework-map.md +5 -4
  178. package/dist/docs/skills/github.html +6 -6
  179. package/dist/docs/skills/github.md +1 -1
  180. package/dist/docs/skills/hillclimb.html +4 -4
  181. package/dist/docs/skills/index.html +6 -6
  182. package/dist/docs/skills/index.md +1 -1
  183. package/dist/docs/skills/mcp-auth.html +4 -4
  184. package/dist/docs/skills/otel.html +4 -4
  185. package/dist/docs/skills/setup-slack.html +4 -4
  186. package/dist/docs/storage.html +8 -8
  187. package/dist/docs/storage.md +15 -24
  188. package/dist/docs/templates/agentic-owners.html +4 -4
  189. package/dist/docs/templates/agents-md.html +4 -4
  190. package/dist/docs/templates/code-wiki.html +4 -4
  191. package/dist/docs/templates/demo.html +4 -4
  192. package/dist/docs/templates/grokbot-agents.html +4 -4
  193. package/dist/docs/templates/pr-autofixer.html +4 -4
  194. package/dist/docs/templates/security-help.html +4 -4
  195. package/dist/docs/templates/security-reviewer.html +4 -4
  196. package/dist/docs/templates/triage.html +4 -4
  197. package/dist/docs/troubleshooting.html +5 -5
  198. package/dist/docs/troubleshooting.md +1 -1
  199. package/dist/extensions/improve/extension.d.ts +46 -0
  200. package/dist/extensions/improve/extension.d.ts.map +1 -0
  201. package/dist/extensions/improve/extension.js +41 -0
  202. package/dist/extensions/improve/skills/yourself.d.ts +4 -0
  203. package/dist/extensions/improve/skills/yourself.d.ts.map +1 -0
  204. package/dist/extensions/improve/skills/yourself.js +43 -0
  205. package/dist/extensions.d.ts +2 -3
  206. package/dist/extensions.d.ts.map +1 -1
  207. package/dist/extensions.js +2 -5
  208. package/dist/index.d.ts +2 -3
  209. package/dist/index.d.ts.map +1 -1
  210. package/dist/index.js +1 -2
  211. package/dist/internal/authored-alias-hooks.d.ts +5 -0
  212. package/dist/internal/authored-alias-hooks.d.ts.map +1 -1
  213. package/dist/internal/authored-alias-hooks.js +17 -0
  214. package/dist/internal/authored-loaders.d.ts +4 -0
  215. package/dist/internal/authored-loaders.d.ts.map +1 -1
  216. package/dist/internal/authored-loaders.js +21 -2
  217. package/dist/internal/builtin-tools/artifacts.d.ts.map +1 -1
  218. package/dist/internal/builtin-tools/artifacts.js +2 -3
  219. package/dist/internal/channel-route-dispatch.d.ts +13 -0
  220. package/dist/internal/channel-route-dispatch.d.ts.map +1 -0
  221. package/dist/internal/channel-route-dispatch.js +62 -0
  222. package/dist/internal/channel-state.d.ts +17 -0
  223. package/dist/internal/channel-state.d.ts.map +1 -0
  224. package/dist/internal/channel-state.js +78 -0
  225. package/dist/internal/cli-ax.d.ts +8 -2
  226. package/dist/internal/cli-ax.d.ts.map +1 -1
  227. package/dist/internal/cli-ax.js +100 -3
  228. package/dist/internal/cli-cursor.d.ts.map +1 -1
  229. package/dist/internal/cli-cursor.js +2 -0
  230. package/dist/internal/cli-deploy.d.ts.map +1 -1
  231. package/dist/internal/cli-deploy.js +38 -14
  232. package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
  233. package/dist/internal/cli-mcp-oauth.js +15 -0
  234. package/dist/internal/cli-mcp.d.ts.map +1 -1
  235. package/dist/internal/cli-mcp.js +12 -0
  236. package/dist/internal/cli-slack.d.ts.map +1 -1
  237. package/dist/internal/cli-slack.js +8 -2
  238. package/dist/internal/continuation-channel.d.ts.map +1 -1
  239. package/dist/internal/continuation-channel.js +2 -2
  240. package/dist/internal/continuation-identity.js +8 -3
  241. package/dist/internal/cursor/credentials.d.ts +8 -2
  242. package/dist/internal/cursor/credentials.d.ts.map +1 -1
  243. package/dist/internal/cursor/credentials.js +27 -5
  244. package/dist/internal/deploy-client.d.ts +27 -0
  245. package/dist/internal/deploy-client.d.ts.map +1 -1
  246. package/dist/internal/deploy-client.js +32 -0
  247. package/dist/internal/deploy-manifest.d.ts +23 -0
  248. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  249. package/dist/internal/deploy-manifest.js +84 -1
  250. package/dist/internal/describe-error.d.ts +1 -0
  251. package/dist/internal/describe-error.d.ts.map +1 -1
  252. package/dist/internal/describe-error.js +25 -0
  253. package/dist/internal/discovery/agent.d.ts +1 -1
  254. package/dist/internal/discovery/agent.d.ts.map +1 -1
  255. package/dist/internal/discovery/agent.js +0 -5
  256. package/dist/internal/discovery/extension-overlay.d.ts +1 -2
  257. package/dist/internal/discovery/extension-overlay.d.ts.map +1 -1
  258. package/dist/internal/discovery/extension-overlay.js +0 -14
  259. package/dist/internal/discovery/extensions.d.ts +1 -2
  260. package/dist/internal/discovery/extensions.d.ts.map +1 -1
  261. package/dist/internal/discovery/extensions.js +4 -22
  262. package/dist/internal/discovery/info.d.ts.map +1 -1
  263. package/dist/internal/discovery/info.js +42 -24
  264. package/dist/internal/discovery/modules.js +0 -1
  265. package/dist/internal/discovery/project.d.ts.map +1 -1
  266. package/dist/internal/discovery/project.js +0 -16
  267. package/dist/internal/eval-runner.js +0 -1
  268. package/dist/internal/framework-file-storage.d.ts +4 -5
  269. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  270. package/dist/internal/framework-file-storage.js +4 -5
  271. package/dist/internal/framework-storage-selection.d.ts +2 -2
  272. package/dist/internal/framework-storage-selection.js +2 -2
  273. package/dist/internal/guest-network.d.ts +4 -10
  274. package/dist/internal/guest-network.d.ts.map +1 -1
  275. package/dist/internal/guest-network.js +42 -26
  276. package/dist/internal/hosted-admission-adapter.d.ts +2 -0
  277. package/dist/internal/hosted-admission-adapter.d.ts.map +1 -1
  278. package/dist/internal/hosted-catch-protocol.d.ts +51 -0
  279. package/dist/internal/hosted-catch-protocol.d.ts.map +1 -0
  280. package/dist/internal/hosted-catch-protocol.js +103 -0
  281. package/dist/internal/hosted-catch.d.ts +40 -0
  282. package/dist/internal/hosted-catch.d.ts.map +1 -0
  283. package/dist/internal/hosted-catch.js +149 -0
  284. package/dist/internal/hosted-delivery-protocol.d.ts +41 -0
  285. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  286. package/dist/internal/hosted-delivery-protocol.js +249 -0
  287. package/dist/internal/hosted-delivery.d.ts +10 -1
  288. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  289. package/dist/internal/hosted-delivery.js +100 -22
  290. package/dist/internal/hosted-execution-diag.d.ts +4 -1
  291. package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
  292. package/dist/internal/hosted-execution-diag.js +13 -4
  293. package/dist/internal/hosted-execution-flush.d.ts +3 -0
  294. package/dist/internal/hosted-execution-flush.d.ts.map +1 -1
  295. package/dist/internal/hosted-execution-flush.js +2 -4
  296. package/dist/internal/http-control-plane-session.d.ts +30 -0
  297. package/dist/internal/http-control-plane-session.d.ts.map +1 -0
  298. package/dist/internal/http-control-plane-session.js +83 -0
  299. package/dist/internal/init-scaffold.d.ts.map +1 -1
  300. package/dist/internal/init-scaffold.js +1 -2
  301. package/dist/internal/install-cursor-skills.d.ts +5 -2
  302. package/dist/internal/install-cursor-skills.d.ts.map +1 -1
  303. package/dist/internal/install-cursor-skills.js +25 -5
  304. package/dist/internal/legacy-command-guard.d.ts +22 -0
  305. package/dist/internal/legacy-command-guard.d.ts.map +1 -0
  306. package/dist/internal/legacy-command-guard.js +51 -0
  307. package/dist/internal/platform-timers.d.ts +7 -0
  308. package/dist/internal/platform-timers.d.ts.map +1 -1
  309. package/dist/internal/platform-timers.js +139 -0
  310. package/dist/internal/reminder-control-plane-protocol.d.ts +2 -0
  311. package/dist/internal/reminder-control-plane-protocol.d.ts.map +1 -1
  312. package/dist/internal/reminder-control-plane-protocol.js +9 -2
  313. package/dist/internal/reminder-runner.d.ts +8 -0
  314. package/dist/internal/reminder-runner.d.ts.map +1 -1
  315. package/dist/internal/reminder-runner.js +36 -9
  316. package/dist/internal/resolve-prod-target.d.ts +2 -0
  317. package/dist/internal/resolve-prod-target.d.ts.map +1 -1
  318. package/dist/internal/resolve-prod-target.js +13 -0
  319. package/dist/internal/run-client.d.ts +1 -1
  320. package/dist/internal/sdk-runner.d.ts.map +1 -1
  321. package/dist/internal/sdk-runner.js +5 -4
  322. package/dist/internal/server.d.ts.map +1 -1
  323. package/dist/internal/server.js +57 -70
  324. package/dist/internal/session-engine.d.ts +7 -41
  325. package/dist/internal/session-engine.d.ts.map +1 -1
  326. package/dist/internal/session-engine.js +110 -227
  327. package/dist/internal/storage-coordinator.d.ts +5 -19
  328. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  329. package/dist/internal/storage-coordinator.js +3 -62
  330. package/dist/internal/storage-roles.d.ts +4 -9
  331. package/dist/internal/storage-roles.d.ts.map +1 -1
  332. package/dist/internal/storage-roles.js +2 -2
  333. package/dist/playground/assets/index-Bhxzrcf6.css +1 -0
  334. package/dist/playground/assets/index-CqLX5uF3.js +67 -0
  335. package/dist/playground/index.html +2 -2
  336. package/dist/storage-backends/cursor-hosted-v2.d.ts +4 -5
  337. package/dist/storage-backends/cursor-hosted-v2.d.ts.map +1 -1
  338. package/dist/storage-backends/cursor-hosted-v2.js +4 -5
  339. package/dist/storage-backends/cursor-hosted.d.ts +7 -2
  340. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  341. package/dist/storage-backends/cursor-hosted.js +29 -31
  342. package/dist/storage-backends/file-kv.d.ts +9 -12
  343. package/dist/storage-backends/file-kv.d.ts.map +1 -1
  344. package/dist/storage-backends/file-kv.js +11 -47
  345. package/dist/storage-protocol.d.ts +3 -11
  346. package/dist/storage-protocol.d.ts.map +1 -1
  347. package/dist/storage-protocol.js +3 -11
  348. package/dist/storage.d.ts +8 -36
  349. package/dist/storage.d.ts.map +1 -1
  350. package/dist/storage.js +8 -44
  351. package/dist/types.d.ts +53 -62
  352. package/dist/types.d.ts.map +1 -1
  353. package/docs/README.md +14 -6
  354. package/docs/building-with-agents.md +3 -2
  355. package/docs/concepts.md +2 -4
  356. package/docs/deployment.md +7 -2
  357. package/docs/evals.md +613 -297
  358. package/docs/guides/bitbucket.md +89 -0
  359. package/docs/guides/cloud-agents.md +4 -3
  360. package/docs/guides/github.md +33 -1
  361. package/docs/guides/gitlab.md +97 -0
  362. package/docs/guides/grokbot-agents.md +2 -2
  363. package/docs/guides/improve.md +96 -0
  364. package/docs/guides/slack.md +2 -1
  365. package/docs/guides/webhooks.md +4 -2
  366. package/docs/hillclimbing.md +2 -2
  367. package/docs/reference/agent-config.md +5 -2
  368. package/docs/reference/channels.md +16 -3
  369. package/docs/reference/cli.md +24 -15
  370. package/docs/reference/connections.md +2 -1
  371. package/docs/reference/extensions.md +2 -3
  372. package/docs/reference/hooks.md +9 -12
  373. package/docs/reference/http-api.md +2 -3
  374. package/docs/reference/playground.md +0 -4
  375. package/docs/reference/project-layout.md +1 -8
  376. package/docs/reference/sessions.md +1 -2
  377. package/docs/scaffolding-agents.md +2 -1
  378. package/docs/skills/index.md +2 -2
  379. package/docs/storage.md +15 -24
  380. package/docs/troubleshooting.md +1 -1
  381. package/package.json +8 -7
  382. package/skills/create-agent/SKILL.md +1 -1
  383. package/skills/debug/SKILL.md +1 -1
  384. package/skills/deploy/SKILL.md +169 -0
  385. package/skills/evals/SKILL.md +45 -8
  386. package/skills/framework-map/SKILL.md +5 -4
  387. package/skills/github/SKILL.md +1 -1
  388. package/src/bin/agent-serve.ts +27 -2
  389. package/src/channels/bitbucket/api.ts +341 -0
  390. package/src/channels/bitbucket/binding.ts +25 -0
  391. package/src/channels/bitbucket/index.ts +2 -0
  392. package/src/channels/github/github-channel.ts +8 -8
  393. package/src/channels/github/types.ts +5 -0
  394. package/src/channels/gitlab/api.ts +123 -0
  395. package/src/channels/gitlab/binding.ts +12 -0
  396. package/src/channels/gitlab/index.ts +1 -0
  397. package/src/channels/origin/origin-channel.ts +29 -13
  398. package/src/channels/origin/types.ts +5 -0
  399. package/src/channels/slack/dispatch.ts +30 -0
  400. package/src/channels/slack/slack-channel.ts +69 -7
  401. package/src/channels.ts +157 -10
  402. package/src/connections.ts +2 -1
  403. package/src/extensions/improve/extension.ts +70 -0
  404. package/src/extensions/improve/skills/yourself.ts +50 -0
  405. package/src/extensions.ts +2 -6
  406. package/src/index.ts +0 -3
  407. package/src/internal/authored-alias-hooks.ts +32 -0
  408. package/src/internal/authored-loaders.ts +26 -2
  409. package/src/internal/builtin-tools/artifacts.ts +2 -3
  410. package/src/internal/channel-route-dispatch.ts +66 -0
  411. package/src/internal/channel-state.ts +96 -0
  412. package/src/internal/cli-ax.ts +111 -3
  413. package/src/internal/cli-cursor.ts +4 -1
  414. package/src/internal/cli-deploy.ts +50 -10
  415. package/src/internal/cli-mcp-oauth.ts +18 -0
  416. package/src/internal/cli-mcp.ts +11 -0
  417. package/src/internal/cli-slack.ts +15 -2
  418. package/src/internal/continuation-channel.ts +2 -1
  419. package/src/internal/continuation-identity.ts +10 -2
  420. package/src/internal/cursor/credentials.ts +35 -7
  421. package/src/internal/deploy-client.ts +54 -0
  422. package/src/internal/deploy-manifest.ts +115 -1
  423. package/src/internal/describe-error.ts +28 -0
  424. package/src/internal/discovery/agent.ts +1 -7
  425. package/src/internal/discovery/extension-overlay.ts +0 -18
  426. package/src/internal/discovery/extensions.ts +2 -26
  427. package/src/internal/discovery/info.ts +3 -13
  428. package/src/internal/discovery/modules.ts +0 -1
  429. package/src/internal/discovery/project.ts +0 -16
  430. package/src/internal/eval-runner.ts +0 -1
  431. package/src/internal/framework-file-storage.ts +4 -5
  432. package/src/internal/framework-storage-selection.ts +2 -2
  433. package/src/internal/guest-network.ts +43 -29
  434. package/src/internal/hosted-admission-adapter.ts +2 -0
  435. package/src/internal/hosted-catch-protocol.ts +130 -0
  436. package/src/internal/hosted-catch.ts +192 -0
  437. package/src/internal/hosted-delivery-protocol.ts +387 -0
  438. package/src/internal/hosted-delivery.ts +155 -22
  439. package/src/internal/hosted-execution-diag.ts +21 -3
  440. package/src/internal/hosted-execution-flush.ts +6 -3
  441. package/src/internal/http-control-plane-session.ts +104 -0
  442. package/src/internal/init-scaffold.ts +1 -2
  443. package/src/internal/install-cursor-skills.ts +38 -5
  444. package/src/internal/legacy-command-guard.ts +59 -0
  445. package/src/internal/platform-timers.ts +191 -0
  446. package/src/internal/reminder-control-plane-protocol.ts +15 -2
  447. package/src/internal/reminder-runner.ts +60 -9
  448. package/src/internal/resolve-prod-target.ts +15 -0
  449. package/src/internal/run-client.ts +1 -1
  450. package/src/internal/sdk-runner.ts +3 -2
  451. package/src/internal/server.ts +89 -95
  452. package/src/internal/session-engine.ts +155 -285
  453. package/src/internal/storage-coordinator.ts +5 -76
  454. package/src/internal/storage-roles.ts +4 -9
  455. package/src/storage-backends/cursor-hosted-v2.ts +4 -7
  456. package/src/storage-backends/cursor-hosted.ts +40 -38
  457. package/src/storage-backends/file-kv.ts +10 -51
  458. package/src/storage-protocol.ts +3 -17
  459. package/src/storage.ts +10 -101
  460. package/src/types.ts +58 -62
  461. package/templates/demo/README.md +10 -6
  462. package/templates/demo/agent/channels/github.ts +2 -0
  463. package/templates/demo/agent/channels/queue.ts +6 -2
  464. package/templates/demo/agent/lib/repos.ts +5 -0
  465. package/templates/demo/init.json +25 -0
  466. package/dist/ab.d.ts +0 -209
  467. package/dist/ab.d.ts.map +0 -1
  468. package/dist/ab.js +0 -246
  469. package/dist/docs/ab.html +0 -80
  470. package/dist/docs/ab.md +0 -332
  471. package/dist/docs/assets/ab.md.mlVgqvSk.js +0 -54
  472. package/dist/docs/assets/ab.md.mlVgqvSk.lean.js +0 -1
  473. package/dist/docs/assets/chunks/@localSearchIndexroot.DXXZxiMv.js +0 -1
  474. package/dist/docs/assets/concepts.md.DgEcZOfT.js +0 -1
  475. package/dist/docs/assets/evals.md.CbMoebP1.js +0 -85
  476. package/dist/docs/assets/evals.md.CbMoebP1.lean.js +0 -1
  477. package/dist/docs/assets/guides_cloud-agents.md.DS8RIjwx.js +0 -9
  478. package/dist/docs/assets/index.md.BW_6tOgR.js +0 -5
  479. package/dist/docs/assets/reference_sessions.md.CueyOHSL.js +0 -1
  480. package/dist/docs/assets/skills_ab.md.CsFNatVx.js +0 -26
  481. package/dist/docs/assets/skills_ab.md.CsFNatVx.lean.js +0 -1
  482. package/dist/docs/assets/skills_evals.md.723kpUmA.js +0 -25
  483. package/dist/docs/assets/skills_evals.md.723kpUmA.lean.js +0 -1
  484. package/dist/docs/assets/skills_framework-map.md.haibFyoB.js +0 -1
  485. package/dist/docs/assets/skills_index.md.DKwIxzGg.js +0 -1
  486. package/dist/docs/assets/skills_index.md.DKwIxzGg.lean.js +0 -1
  487. package/dist/docs/assets/troubleshooting.md.Cus_YZga.js +0 -1
  488. package/dist/docs/skills/ab.html +0 -52
  489. package/dist/docs/skills/ab.md +0 -50
  490. package/dist/internal/ab-collector.d.ts +0 -44
  491. package/dist/internal/ab-collector.d.ts.map +0 -1
  492. package/dist/internal/ab-collector.js +0 -142
  493. package/dist/internal/ab-fold.d.ts +0 -36
  494. package/dist/internal/ab-fold.d.ts.map +0 -1
  495. package/dist/internal/ab-fold.js +0 -175
  496. package/dist/internal/ab-snapshot.d.ts +0 -68
  497. package/dist/internal/ab-snapshot.d.ts.map +0 -1
  498. package/dist/internal/ab-snapshot.js +0 -208
  499. package/dist/internal/discovery/ab.d.ts +0 -9
  500. package/dist/internal/discovery/ab.d.ts.map +0 -1
  501. package/dist/internal/discovery/ab.js +0 -113
  502. package/dist/playground/assets/index-Bq2HpEQB.js +0 -67
  503. package/dist/playground/assets/index-CZKKNlmb.css +0 -1
  504. package/docs/ab.md +0 -337
  505. package/skills/ab/SKILL.md +0 -58
  506. package/src/ab.ts +0 -430
  507. package/src/internal/ab-collector.ts +0 -200
  508. package/src/internal/ab-fold.ts +0 -232
  509. package/src/internal/ab-snapshot.ts +0 -331
  510. package/src/internal/discovery/ab.ts +0 -131
  511. /package/dist/docs/assets/{concepts.md.DgEcZOfT.lean.js → concepts.md.B4o63Gul.lean.js} +0 -0
  512. /package/dist/docs/assets/{guides_grokbot-agents.md.DVqdhBKb.lean.js → guides_grokbot-agents.md.DyV-WArv.lean.js} +0 -0
  513. /package/dist/docs/assets/{guides_webhooks.md.DKdA43Qm.lean.js → guides_webhooks.md.CJK484ex.lean.js} +0 -0
  514. /package/dist/docs/assets/{hillclimbing.md.CpTGTCle.lean.js → hillclimbing.md.BOiVo1tf.lean.js} +0 -0
  515. /package/dist/docs/assets/{reference_agent-config.md.CHNpiyp4.lean.js → reference_agent-config.md.CvoL6pof.lean.js} +0 -0
  516. /package/dist/docs/assets/{reference_connections.md.Di6jJAXF.lean.js → reference_connections.md.BojkC6c5.lean.js} +0 -0
  517. /package/dist/docs/assets/{reference_extensions.md.CGmMLblt.lean.js → reference_extensions.md.ZAVUyuEX.lean.js} +0 -0
  518. /package/dist/docs/assets/{reference_http-api.md.oySXBO8o.lean.js → reference_http-api.md.BwaCo-VO.lean.js} +0 -0
  519. /package/dist/docs/assets/{reference_sessions.md.CueyOHSL.lean.js → reference_sessions.md.CyXV1MUw.lean.js} +0 -0
  520. /package/dist/docs/assets/{scaffolding-agents.md.em43xlY1.lean.js → scaffolding-agents.md.Kctn3OVb.lean.js} +0 -0
  521. /package/dist/docs/assets/{skills_create-agent.md.BVoWPcan.lean.js → skills_create-agent.md.Q3h6Je-e.lean.js} +0 -0
  522. /package/dist/docs/assets/{skills_github.md.D0JahM8c.lean.js → skills_github.md.hgFX_oKY.lean.js} +0 -0
  523. /package/dist/docs/assets/{troubleshooting.md.Cus_YZga.lean.js → troubleshooting.md.CYEAO9bM.lean.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  import{_ as t,c as e,o as a,ag as i}from"./chunks/framework.BCISBCiQ.js";const k=JSON.parse('{"title":"Extensions","description":"Mount a package of agent contributions or a Cursor plugin under a namespace with one file, adjust what it contributes, and author your own as a directory laid out like agent/.","frontmatter":{"title":"Extensions","description":"Mount a package of agent contributions or a Cursor plugin under a namespace with one file, adjust what it contributes, and author your own as a directory laid out like agent/."},"headers":[],"relativePath":"reference/extensions.md","filePath":"reference/extensions.md"}'),n={name:"reference/extensions.md"};function o(l,s,d,h,p,r){return a(),e("div",null,[...s[0]||(s[0]=[i(`<h1 id="extensions" tabindex="-1">Extensions <a class="header-anchor" href="#extensions" aria-label="Permalink to &quot;Extensions&quot;">​</a></h1><p>An extension packages the same contributions an agent authors under <code>agent/</code> and installs them as one unit. You mount it with a single file under <code>agent/extensions/</code>, and its contributions join the agent under a namespace. The package updates like any other dependency; nothing is copied into your project. A Cursor plugin mounts the same way; see <a href="#mount-a-cursor-plugin">Mount a Cursor plugin</a>.</p><p>Extensions are native to the Agent SDK. Slot files use the <code>@cursor/july</code> helpers, so a package built on another agent framework fails <code>agent-sdk validate</code> until you rewrite it onto <code>@cursor/july</code>.</p><h2 id="mount-an-extension" tabindex="-1">Mount an extension <a class="header-anchor" href="#mount-an-extension" aria-label="Permalink to &quot;Mount an extension&quot;">​</a></h2><p>Install the package, then add one file. The filename is the namespace.</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:#6A737D;--shiki-dark:#6A737D;">// agent/extensions/ci.ts</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;"> ci </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@acme/ci-triage&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
3
3
  <span class="line"></span>
4
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ci</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ org: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;acme&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, token: process.env.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">BUILDKITE_TOKEN</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span></code></pre></div><p>Every contribution is exposed as <code>&lt;namespace&gt;__&lt;name&gt;</code>. A <code>failed_jobs</code> tool from this mount runs in the agent as <code>ci__failed_jobs</code>, and a <code>triage</code> skill loads as <code>ci__triage</code>. <code>agent-sdk info</code> lists each mount with what it contributed, and <code>GET /v1/info</code> returns the same under <code>extensions</code>.</p><p>Pass the configuration the extension asks for. The extension validates it when the agent loads, so a missing or mistyped field fails <code>agent-sdk validate</code> instead of a tool call later.</p><p>Namespaces follow the tool-name rule, and <code>__</code> is reserved: an authored <code>agent/tools/ci__failed_jobs.ts</code> fails discovery, so nothing outside a mount can pose as one of its tools.</p><h2 id="what-an-extension-can-contribute" tabindex="-1">What an extension can contribute <a class="header-anchor" href="#what-an-extension-can-contribute" aria-label="Permalink to &quot;What an extension can contribute&quot;">​</a></h2><p>An extension tree uses the same slots as <a href="./project-layout.html"><code>agent/</code></a>. Each shareable contribution lands on the agent under the mount&#39;s namespace:</p><table tabindex="0"><thead><tr><th>Path</th><th>Becomes</th></tr></thead><tbody><tr><td><code>tools/&lt;name&gt;.ts</code></td><td>tool <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>skills/&lt;name&gt;</code></td><td>skill <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>mcp-connections/&lt;name&gt;.ts</code></td><td>connection <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>host-connections/&lt;name&gt;.ts</code></td><td>host connection <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>hooks/&lt;name&gt;.ts</code></td><td>hook <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>channels/&lt;name&gt;.ts</code></td><td>channel <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>schedules/&lt;name&gt;</code></td><td>schedule <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>subagents/&lt;id&gt;/</code></td><td>subagent <code>&lt;ns&gt;__&lt;id&gt;</code></td></tr><tr><td><code>instructions.md</code> / <code>.ts</code> / dir</td><td>appended to the agent&#39;s system prompt</td></tr><tr><td><code>sandbox/workspace/**</code></td><td>seeded into each local session workspace</td></tr><tr><td><code>ab.ts</code> / <code>ab/&lt;name&gt;.ts</code></td><td>A/B experiment <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>artifacts.ts</code></td><td>artifact kinds <code>&lt;ns&gt;__&lt;kind&gt;</code></td></tr></tbody></table><p>The root agent still needs its own <code>instructions.md</code>. Extension instructions are extra fragments, not a substitute.</p><p><code>httpChannel()</code> stays on the agent. An extension authors <code>defineChannel</code> only; a file named <code>http.ts</code> becomes <code>&lt;ns&gt;__http</code>.</p><p>These stay on the agent that mounts the extension. Each is a singleton or is outside discovery:</p><table tabindex="0"><thead><tr><th>Path</th><th>Why it stays on the agent</th></tr></thead><tbody><tr><td><code>agent.ts</code></td><td>One <code>defineAgent</code> runtime per agent</td></tr><tr><td><code>storage.ts</code></td><td>One <code>host.kv</code> / <code>host.files</code> backend</td></tr><tr><td><code>otel.ts</code></td><td>One OTLP exporter</td></tr><tr><td><code>ab.config.ts</code></td><td>One experiment-platform config; <code>ab.ts</code> / <code>ab/</code> still merge</td></tr><tr><td><code>playground/</code></td><td>Custom chips are a Vite glob of the agent tree, not a discovery walk</td></tr><tr><td><code>extensions/</code></td><td>Nested mounts are not loaded</td></tr><tr><td><code>sandbox.ts</code></td><td>Custom sandbox backends stay on the agent</td></tr></tbody></table><p><code>agent-sdk validate</code> warns when a tree carries those paths.</p><h2 id="adjust-a-mounted-extension" tabindex="-1">Adjust a mounted extension <a class="header-anchor" href="#adjust-a-mounted-extension" aria-label="Permalink to &quot;Adjust a mounted extension&quot;">​</a></h2><p>To replace or remove a contribution, mount the extension as a directory and overlay the slot you want to change.</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>agent/extensions/ci/</span></span>
4
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ci</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ org: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;acme&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, token: process.env.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">BUILDKITE_TOKEN</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span></code></pre></div><p>Every contribution is exposed as <code>&lt;namespace&gt;__&lt;name&gt;</code>. A <code>failed_jobs</code> tool from this mount runs in the agent as <code>ci__failed_jobs</code>, and a <code>triage</code> skill loads as <code>ci__triage</code>. <code>agent-sdk info</code> lists each mount with what it contributed, and <code>GET /v1/info</code> returns the same under <code>extensions</code>.</p><p>Pass the configuration the extension asks for. The extension validates it when the agent loads, so a missing or mistyped field fails <code>agent-sdk validate</code> instead of a tool call later.</p><p>Namespaces follow the tool-name rule, and <code>__</code> is reserved: an authored <code>agent/tools/ci__failed_jobs.ts</code> fails discovery, so nothing outside a mount can pose as one of its tools.</p><h2 id="what-an-extension-can-contribute" tabindex="-1">What an extension can contribute <a class="header-anchor" href="#what-an-extension-can-contribute" aria-label="Permalink to &quot;What an extension can contribute&quot;">​</a></h2><p>An extension tree uses the same slots as <a href="./project-layout.html"><code>agent/</code></a>. Each shareable contribution lands on the agent under the mount&#39;s namespace:</p><table tabindex="0"><thead><tr><th>Path</th><th>Becomes</th></tr></thead><tbody><tr><td><code>tools/&lt;name&gt;.ts</code></td><td>tool <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>skills/&lt;name&gt;</code></td><td>skill <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>mcp-connections/&lt;name&gt;.ts</code></td><td>connection <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>host-connections/&lt;name&gt;.ts</code></td><td>host connection <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>hooks/&lt;name&gt;.ts</code></td><td>hook <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>channels/&lt;name&gt;.ts</code></td><td>channel <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>schedules/&lt;name&gt;</code></td><td>schedule <code>&lt;ns&gt;__&lt;name&gt;</code></td></tr><tr><td><code>subagents/&lt;id&gt;/</code></td><td>subagent <code>&lt;ns&gt;__&lt;id&gt;</code></td></tr><tr><td><code>instructions.md</code> / <code>.ts</code> / dir</td><td>appended to the agent&#39;s system prompt</td></tr><tr><td><code>sandbox/workspace/**</code></td><td>seeded into each local session workspace</td></tr><tr><td><code>artifacts.ts</code></td><td>artifact kinds <code>&lt;ns&gt;__&lt;kind&gt;</code></td></tr></tbody></table><p>The root agent still needs its own <code>instructions.md</code>. Extension instructions are extra fragments, not a substitute.</p><p><code>httpChannel()</code> stays on the agent. An extension authors <code>defineChannel</code> only; a file named <code>http.ts</code> becomes <code>&lt;ns&gt;__http</code>.</p><p>These stay on the agent that mounts the extension. Each is a singleton or is outside discovery:</p><table tabindex="0"><thead><tr><th>Path</th><th>Why it stays on the agent</th></tr></thead><tbody><tr><td><code>agent.ts</code></td><td>One <code>defineAgent</code> runtime per agent</td></tr><tr><td><code>storage.ts</code></td><td>One <code>host.kv</code> / <code>host.files</code> backend</td></tr><tr><td><code>otel.ts</code></td><td>One OTLP exporter</td></tr><tr><td><code>playground/</code></td><td>Custom chips are a Vite glob of the agent tree, not a discovery walk</td></tr><tr><td><code>extensions/</code></td><td>Nested mounts are not loaded</td></tr><tr><td><code>sandbox.ts</code></td><td>Custom sandbox backends stay on the agent</td></tr></tbody></table><p><code>agent-sdk validate</code> warns when a tree carries those paths.</p><h2 id="adjust-a-mounted-extension" tabindex="-1">Adjust a mounted extension <a class="header-anchor" href="#adjust-a-mounted-extension" aria-label="Permalink to &quot;Adjust a mounted extension&quot;">​</a></h2><p>To replace or remove a contribution, mount the extension as a directory and overlay the slot you want to change.</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>agent/extensions/ci/</span></span>
5
5
  <span class="line"><span>├── extension.ts # the mount: export default ci({ ... })</span></span>
6
6
  <span class="line"><span>├── tools/</span></span>
7
7
  <span class="line"><span>│ ├── job_log.ts # replaces ci__job_log with your own defineTool</span></span>
@@ -9,7 +9,7 @@ import{_ as t,c as e,o as a,ag as i}from"./chunks/framework.BCISBCiQ.js";const k
9
9
  <span class="line"><span>├── hooks/</span></span>
10
10
  <span class="line"><span>│ └── audit.ts # export default disableHook() removes ci__audit</span></span>
11
11
  <span class="line"><span>└── skills/</span></span>
12
- <span class="line"><span> └── triage.ts # export default disableSkill() removes ci__triage</span></span></code></pre></div><p>Use the extension&#39;s own names inside the directory, without the namespace. A file with a name the extension doesn&#39;t contribute adds a new contribution under the namespace. Each helper comes from <code>@cursor/july/extensions</code> and fails discovery when it names a contribution the extension doesn&#39;t have, so a typo can&#39;t silently keep it alive.</p><table tabindex="0"><thead><tr><th>Slot</th><th>Helper</th></tr></thead><tbody><tr><td><code>tools/&lt;name&gt;.ts</code></td><td><code>disableTool()</code></td></tr><tr><td><code>mcp-connections/&lt;name&gt;.ts</code> / <code>host-connections/&lt;name&gt;.ts</code></td><td><code>disableConnection()</code></td></tr><tr><td><code>skills/&lt;name&gt;.ts</code></td><td><code>disableSkill()</code></td></tr><tr><td><code>hooks/&lt;name&gt;.ts</code></td><td><code>disableHook()</code></td></tr><tr><td><code>channels/&lt;name&gt;.ts</code></td><td><code>disableChannel()</code></td></tr><tr><td><code>schedules/&lt;name&gt;.ts</code></td><td><code>disableSchedule()</code></td></tr><tr><td><code>subagents/&lt;id&gt;.ts</code></td><td><code>disableSubagent()</code></td></tr><tr><td><code>instructions.ts</code></td><td><code>disableInstructions()</code></td></tr><tr><td><code>ab.ts</code> / <code>ab/&lt;name&gt;.ts</code></td><td><code>disableAB()</code></td></tr><tr><td><code>artifacts.ts</code></td><td><code>disableArtifacts()</code></td></tr></tbody></table><p><code>disable()</code> is the same brand as the slot helpers above and works in any of those files.</p><p>A Cursor plugin mount overlays its MCP servers the same way; see below.</p><h2 id="mount-a-cursor-plugin" tabindex="-1">Mount a Cursor plugin <a class="header-anchor" href="#mount-a-cursor-plugin" aria-label="Permalink to &quot;Mount a Cursor plugin&quot;">​</a></h2><p>A Cursor plugin is a directory with <code>.cursor-plugin/plugin.json</code> (or <code>.claude-plugin/plugin.json</code>, or <code>plugin.json</code>) and any of <code>skills/</code>, <code>commands/</code>, <code>agents/</code>, and <code>mcp.json</code>. Copy the plugin into your project and mount it with <code>cursorPlugin</code>. The filename is the namespace, as with any extension.</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:#6A737D;--shiki-dark:#6A737D;">// agent/extensions/notion.ts</span></span>
12
+ <span class="line"><span> └── triage.ts # export default disableSkill() removes ci__triage</span></span></code></pre></div><p>Use the extension&#39;s own names inside the directory, without the namespace. A file with a name the extension doesn&#39;t contribute adds a new contribution under the namespace. Each helper comes from <code>@cursor/july/extensions</code> and fails discovery when it names a contribution the extension doesn&#39;t have, so a typo can&#39;t silently keep it alive.</p><table tabindex="0"><thead><tr><th>Slot</th><th>Helper</th></tr></thead><tbody><tr><td><code>tools/&lt;name&gt;.ts</code></td><td><code>disableTool()</code></td></tr><tr><td><code>mcp-connections/&lt;name&gt;.ts</code> / <code>host-connections/&lt;name&gt;.ts</code></td><td><code>disableConnection()</code></td></tr><tr><td><code>skills/&lt;name&gt;.ts</code></td><td><code>disableSkill()</code></td></tr><tr><td><code>hooks/&lt;name&gt;.ts</code></td><td><code>disableHook()</code></td></tr><tr><td><code>channels/&lt;name&gt;.ts</code></td><td><code>disableChannel()</code></td></tr><tr><td><code>schedules/&lt;name&gt;.ts</code></td><td><code>disableSchedule()</code></td></tr><tr><td><code>subagents/&lt;id&gt;.ts</code></td><td><code>disableSubagent()</code></td></tr><tr><td><code>instructions.ts</code></td><td><code>disableInstructions()</code></td></tr><tr><td><code>artifacts.ts</code></td><td><code>disableArtifacts()</code></td></tr></tbody></table><p><code>disable()</code> is the same brand as the slot helpers above and works in any of those files.</p><p>A Cursor plugin mount overlays its MCP servers the same way; see below.</p><h2 id="mount-a-cursor-plugin" tabindex="-1">Mount a Cursor plugin <a class="header-anchor" href="#mount-a-cursor-plugin" aria-label="Permalink to &quot;Mount a Cursor plugin&quot;">​</a></h2><p>A Cursor plugin is a directory with <code>.cursor-plugin/plugin.json</code> (or <code>.claude-plugin/plugin.json</code>, or <code>plugin.json</code>) and any of <code>skills/</code>, <code>commands/</code>, <code>agents/</code>, and <code>mcp.json</code>. Copy the plugin into your project and mount it with <code>cursorPlugin</code>. The filename is the namespace, as with any extension.</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:#6A737D;--shiki-dark:#6A737D;">// agent/extensions/notion.ts</span></span>
13
13
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { cursorPlugin } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july/extensions&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
14
14
  <span class="line"></span>
15
15
  <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;"> cursorPlugin</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
@@ -59,4 +59,4 @@ import{_ as t,c as e,o as a,ag as i}from"./chunks/framework.BCISBCiQ.js";const k
59
59
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">org</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">token</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">logTailLines</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> extension.config;</span></span>
60
60
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> jobLogTail</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ org, token, pipeline, build, job, lines: logTailLines });</span></span>
61
61
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
62
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Because the consumer picks the namespace, have skills and tool descriptions refer to sibling tools by their short names and say they appear under the mount&#39;s namespace (<code>&lt;namespace&gt;__job_log</code>).</p><p>Publish the built <code>extension.js</code> as the package entry point with the slot directories beside it. <code>root</code> is read from the built file, so copy <code>skills/*.md</code> and <code>instructions.md</code> into the build output or author them as <code>.ts</code>.</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/cloud-agents.html">Cursor cloud agents</a>: the extension that lets an agent launch and steer cloud agents</li><li><a href="./../guides/grokbot-agents.html">Cursor Grok Bot agents</a>: the extension that lets an agent talk to Grok Bot agents</li><li><a href="./tools.html">Tools</a>: the tool contract extensions contribute to</li><li><a href="./skills.html">Skills</a>: the skill forms an extension can carry</li><li><a href="./project-layout.html">Project layout</a>: where <code>agent/extensions/</code> sits in the tree</li></ul>`,46)])])}const g=t(n,[["render",o]]);export{k as __pageData,g as default};
62
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Because the consumer picks the namespace, have skills and tool descriptions refer to sibling tools by their short names and say they appear under the mount&#39;s namespace (<code>&lt;namespace&gt;__job_log</code>).</p><p>Publish the built <code>extension.js</code> as the package entry point with the slot directories beside it. <code>root</code> is read from the built file, so copy <code>skills/*.md</code> and <code>instructions.md</code> into the build output or author them as <code>.ts</code>.</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/cloud-agents.html">Cursor cloud agents</a>: the extension that lets an agent launch and steer cloud agents</li><li><a href="./../guides/grokbot-agents.html">Cursor Grok Bot agents</a>: the extension that lets an agent talk to Grok Bot agents</li><li><a href="./../guides/improve.html">Self-improvement</a>: the extension that lets an agent change its own source through a cloud agent and a pull request</li><li><a href="./tools.html">Tools</a>: the tool contract extensions contribute to</li><li><a href="./skills.html">Skills</a>: the skill forms an extension can carry</li><li><a href="./project-layout.html">Project layout</a>: where <code>agent/extensions/</code> sits in the tree</li></ul>`,46)])])}const g=t(n,[["render",o]]);export{k as __pageData,g as default};
@@ -1,4 +1,4 @@
1
- import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.BCISBCiQ.js";const c=JSON.parse('{"title":"Hooks","description":"Observe-only subscribers to the session event stream: audit logs, metrics, transcript mirrors, derived state.","frontmatter":{"title":"Hooks","description":"Observe-only subscribers to the session event stream: audit logs, metrics, transcript mirrors, derived state."},"headers":[],"relativePath":"reference/hooks.md","filePath":"reference/hooks.md"}'),n={name:"reference/hooks.md"};function h(o,s,l,d,r,p){return a(),t("div",null,[...s[0]||(s[0]=[i(`<h1 id="hooks" tabindex="-1">Hooks <a class="header-anchor" href="#hooks" aria-label="Permalink to &quot;Hooks&quot;">​</a></h1><p>A hook subscribes to the session event stream and runs a side effect after each event is recorded: an audit line, a metric, a copy of the transcript in your own store, or derived state for later turns. Hooks run in the serving process for every session of the agent, on local and cloud runtime turns alike.</p><p>Hooks observe. They can&#39;t change the turn, the prompt, or the reply, and a handler that throws is logged and skipped. Treat the event as read-only; later subscribers see the same object. That makes hooks safe to add to a production agent, and the wrong tool for anything that must happen before the model runs or must fail a turn; see <a href="#when-not-to-use-a-hook">When not to use a hook</a>.</p><p><code>defineHook</code> is unrelated to <a href="https://cursor.com/docs/agent/hooks" target="_blank" rel="noreferrer">Cursor Agent hooks</a>, the <code>.cursor/hooks.json</code> scripts that can observe, block, or modify the agent loop. Those still run inside a local session workspace.</p><h2 id="author-a-hook" tabindex="-1">Author a hook <a class="header-anchor" href="#author-a-hook" aria-label="Permalink to &quot;Author a hook&quot;">​</a></h2><p>Author <code>agent/hooks/&lt;name&gt;.ts</code> with <code>defineHook</code> from <code>@cursor/july/hooks</code>. This one meters tokens:</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:#6A737D;--shiki-dark:#6A737D;">// agent/hooks/usage.ts</span></span>
1
+ import{_ as e,c as a,o as t,ag as i}from"./chunks/framework.BCISBCiQ.js";const c=JSON.parse('{"title":"Hooks","description":"Observe-only subscribers to the session event stream: audit logs, metrics, transcript mirrors, derived state.","frontmatter":{"title":"Hooks","description":"Observe-only subscribers to the session event stream: audit logs, metrics, transcript mirrors, derived state."},"headers":[],"relativePath":"reference/hooks.md","filePath":"reference/hooks.md"}'),n={name:"reference/hooks.md"};function h(o,s,l,d,r,p){return t(),a("div",null,[...s[0]||(s[0]=[i(`<h1 id="hooks" tabindex="-1">Hooks <a class="header-anchor" href="#hooks" aria-label="Permalink to &quot;Hooks&quot;">​</a></h1><p>A hook subscribes to the session event stream and runs a side effect after each event is recorded: an audit line, a metric, a copy of the transcript in your own store, or derived state for later turns. Hooks run in the serving process for every session of the agent, on local and cloud runtime turns alike.</p><p>Hooks observe. They can&#39;t change the turn, the prompt, or the reply, and a handler that throws is logged and skipped. Treat the event as read-only; later subscribers see the same object. That makes hooks safe to add to a production agent, and the wrong tool for anything that must happen before the model runs or must fail a turn; see <a href="#when-not-to-use-a-hook">When not to use a hook</a>.</p><p><code>defineHook</code> is unrelated to <a href="https://cursor.com/docs/agent/hooks" target="_blank" rel="noreferrer">Cursor Agent hooks</a>, the <code>.cursor/hooks.json</code> scripts that can observe, block, or modify the agent loop. Those still run inside a local session workspace.</p><h2 id="author-a-hook" tabindex="-1">Author a hook <a class="header-anchor" href="#author-a-hook" aria-label="Permalink to &quot;Author a hook&quot;">​</a></h2><p>Author <code>agent/hooks/&lt;name&gt;.ts</code> with <code>defineHook</code> from <code>@cursor/july/hooks</code>. This one meters tokens:</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:#6A737D;--shiki-dark:#6A737D;">// agent/hooks/usage.ts</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;"> { defineHook } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july/hooks&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;"> defineHook</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
@@ -15,7 +15,7 @@ import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.BCISBCiQ.js";const c
15
15
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ctx.host.otel.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">increment</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;acme.turn.failed&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { channel: ctx.channel.id });</span></span>
16
16
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
17
17
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
18
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Any module under <code>agent/hooks/</code>, subfolders included, is a hook named by its path without the extension: <code>agent/hooks/audit/usage.ts</code> is <code>audit/usage</code>. <code>*.test.ts</code> and <code>*.spec.ts</code> files are skipped. The default export must be <code>defineHook(...)</code>, names can&#39;t contain <code>__</code>, and an empty <code>events</code> map skips the hook with a warning; <code>agent-sdk validate</code> reports all three. An extension mounts its hooks as <code>&lt;ns&gt;__&lt;name&gt;</code>, and <code>disableHook()</code> removes one (<a href="./extensions.html#adjust-a-mounted-extension">Adjust a mounted extension</a>).</p><p><code>agent-sdk init</code> scaffolds <code>agent/hooks/memory.ts</code>, which exports <code>memoryHook()</code> from <code>@cursor/july/memory</code> and journals every turn for later sessions to read. Delete the file to opt out.</p><h2 id="events-and-payloads" tabindex="-1">Events and payloads <a class="header-anchor" href="#events-and-payloads" aria-label="Permalink to &quot;Events and payloads&quot;">​</a></h2><p>Keys are event types from the <a href="./sessions.html#which-events-can-i-stream">event vocabulary</a>, or <code>&quot;*&quot;</code> for every event. A typed key narrows <code>event.data</code>; a <code>&quot;*&quot;</code> handler receives the union, so switch on <code>event.type</code>. Every event carries the stream envelope <code>{ type, index, sessionId, turnId?, at, data }</code>, with <code>turnId</code> set on turn-scoped events.</p><p>The payloads hooks read most often:</p><table tabindex="0"><thead><tr><th>Event</th><th><code>event.data</code></th></tr></thead><tbody><tr><td><code>message.received</code></td><td><code>{ text }</code></td></tr><tr><td><code>turn.completed</code></td><td><code>{ result?, usage?, cost? }</code>. <code>usage</code> has <code>inputTokens</code>, <code>outputTokens</code>, <code>cacheReadTokens</code>, <code>cacheWriteTokens</code>, and optional <code>reasoningTokens</code>. <code>cost</code> has <code>totalUsd</code> and the <code>model</code> it was priced against</td></tr><tr><td><code>turn.failed</code></td><td><code>{ message }</code></td></tr><tr><td><code>actions.requested</code></td><td><code>{ calls: [{ callId, toolName, args? }] }</code>. A call with <code>parentCallId</code> belongs to a subagent</td></tr><tr><td><code>action.result</code></td><td><code>{ callId, toolName, output?, isError, stubbed? }</code>. <code>stubbed</code> means a dry-run session answered a write without running it</td></tr></tbody></table><p>The types are <code>SessionEvent</code>, <code>SessionEventType</code>, and <code>HookContext</code>, exported from <code>@cursor/july</code>.</p><h2 id="handler-context" tabindex="-1">Handler context <a class="header-anchor" href="#handler-context" aria-label="Permalink to &quot;Handler context&quot;">​</a></h2><table tabindex="0"><thead><tr><th>Member</th><th>What it is</th></tr></thead><tbody><tr><td><code>ctx.session</code></td><td>Read-only session info: <code>id</code>, <code>channelId</code>, <code>mode</code> (<code>chat</code> or <code>task</code>), <code>purpose</code> (<code>live</code> or <code>eval</code>), <code>auth</code>, plus <code>title</code>, <code>sdkAgentId</code>, and <code>abs</code> when set</td></tr><tr><td><code>ctx.agent</code></td><td><code>{ name }</code> of the agent the event belongs to</td></tr><tr><td><code>ctx.channel</code></td><td><code>{ id, continuationToken }</code>. The token is <code>null</code> when the session can&#39;t take follow-ups</td></tr><tr><td><code>ctx.host.kv</code></td><td>Durable JSON, shared by every session of the agent; the <a href="./../storage.html#author-kv-ctx-host-kv">storage backend</a> decides whether it survives a hosted replace. Prefix keys with <code>ctx.session.id</code> for per-session state</td></tr><tr><td><code>ctx.host.files</code></td><td>Durable files, bound to this session. Pass <code>{ scope: &quot;deployment&quot; }</code> for agent-wide files</td></tr><tr><td><code>ctx.host.otel</code></td><td>Counters, histograms, and tags, attributed to this session</td></tr><tr><td><code>ctx.host.mcp</code>, <code>ctx.host.github</code>, <code>ctx.host.slack</code></td><td>The same shared clients tools get</td></tr><tr><td><code>ctx.host.reminders</code></td><td>Per-session <a href="./schedules.html">reminders</a>, the same API tools get</td></tr><tr><td><code>ctx.artifacts</code></td><td>Session-bound <a href="./artifacts.html">artifacts</a> facade: <code>tag</code> fills in <code>sessionId</code> and <code>turnId</code></td></tr><tr><td><code>ctx.stateRoot</code></td><td>Absolute path of the local state root. It resets when a hosted deployment is replaced; keep derived state in <code>kv</code> or <code>files</code></td></tr></tbody></table><h2 id="when-hooks-run" tabindex="-1">When hooks run <a class="header-anchor" href="#when-hooks-run" aria-label="Permalink to &quot;When hooks run&quot;">​</a></h2><p>A hook runs after the event is durably recorded. It never delays the model turn and never sees an event that wasn&#39;t recorded.</p><p>Within one session, events dispatch in order, one at a time: the channel&#39;s <code>events</code> handlers first, then each hook in discovery order. Sessions don&#39;t wait on each other.</p><p>Two consequences:</p><ul><li>A slow handler holds up the next event&#39;s handlers for that session, not the model. Keep handlers short and queue anything slow.</li><li>Hooks fire for eval sessions too. Check <code>ctx.session.purpose === &quot;eval&quot;</code> before metering or paging.</li></ul><p>Each event reaches a hook at most once. A restart doesn&#39;t replay the log into hooks, so a mirror needs no dedupe, and the event log rather than the hook&#39;s copy is the source of truth.</p><h2 id="hooks-channel-events-evals-or-a-b" tabindex="-1">Hooks, channel events, evals, or A/B? <a class="header-anchor" href="#hooks-channel-events-evals-or-a-b" aria-label="Permalink to &quot;Hooks, channel events, evals, or A/B?&quot;">​</a></h2><p>All of them consume the same stream, for different jobs:</p><table tabindex="0"><thead><tr><th></th><th>Hooks</th><th>Channel <code>events</code></th><th>Evals</th><th>A/B (<code>defineAB</code>)</th></tr></thead><tbody><tr><td>Scope</td><td>every session of the agent</td><td>sessions the channel owns</td><td>one test turn</td><td>every live session; enrollment at creation, metrics on each turn</td></tr><tr><td>Job</td><td>observe: audit, metrics, mirrors, derived state</td><td>deliver: replies back to the channel&#39;s surface</td><td>assert: gates over the trajectory</td><td>compare: sticky arms, then fold the stream into <code>onSample</code> metrics</td></tr><tr><td>Context</td><td><code>ctx.host</code>, <code>ctx.artifacts</code>, session info</td><td><code>channel.state</code>, <code>setContinuationToken</code>, <code>ctx.host</code>, session info</td><td>the <code>t</code> assertion helpers</td><td>per-session samples in <code>onSample</code></td></tr><tr><td>Can affect the run</td><td>no</td><td>yes, it owns the surface</td><td>n/a</td><td>yes through arm instructions or <code>session.abs</code>; collection is observe-only</td></tr><tr><td>Authored at</td><td><code>agent/hooks/*.ts</code></td><td>channel config</td><td><code>evals/**/*.eval.ts</code></td><td><a href="./../ab.html"><code>agent/ab.ts</code> or <code>agent/ab/*.ts</code></a></td></tr></tbody></table><h2 id="when-not-to-use-a-hook" tabindex="-1">When not to use a hook <a class="header-anchor" href="#when-not-to-use-a-hook" aria-label="Permalink to &quot;When not to use a hook&quot;">​</a></h2><table tabindex="0"><thead><tr><th>You want to</th><th>Use instead</th></tr></thead><tbody><tr><td>Add context before the model runs</td><td>The channel&#39;s <code>send</code> message and <code>workspaceFiles</code>, <code>instructions.md</code>, skills, or <code>sandbox/workspace/</code> seed files</td></tr><tr><td>Reply on Slack, comment on a PR, or post any other delivery</td><td>The channel&#39;s <code>events</code> map, or the Slack and GitHub packs</td></tr><tr><td>Show PR progress (merge-box check, sticky banner)</td><td><code>githubChannel({ progress: { commitStatus, banner } })</code>; see <a href="./../guides/github.html#show-pr-progress">Show PR progress</a></td></tr><tr><td>Block, approve, or rewrite a tool call</td><td><a href="./tools.html#gate-a-tool-on-human-approval"><code>needsApproval</code></a> on the tool</td></tr><tr><td>Act on the final assistant text, or fail a bad turn</td><td><a href="./result.html"><code>defineResult</code></a></td></tr><tr><td>Gate a change on behavior</td><td><a href="./../evals.html">Evals</a></td></tr><tr><td>Compare two prompts on live traffic</td><td><a href="./../ab.html"><code>defineAB</code></a></td></tr></tbody></table><h2 id="patterns" tabindex="-1">Patterns <a class="header-anchor" href="#patterns" aria-label="Permalink to &quot;Patterns&quot;">​</a></h2><p>Usage metering is the <a href="#author-a-hook">authoring example</a>. Three more:</p><h3 id="alert-on-failure" tabindex="-1">Alert on failure <a class="header-anchor" href="#alert-on-failure" aria-label="Permalink to &quot;Alert on failure&quot;">​</a></h3><p><code>turn.failed</code> carries the message, and <code>ctx.session.id</code> points at the trace. Skip interrupted turns; those are preemptions, not failures. Read secrets inside the handler: hosted deployments bind them after the process starts, so a module-scope read stays empty. Give the call a timeout, since a stalled request holds up later handlers on that session.</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:#6A737D;--shiki-dark:#6A737D;">// agent/hooks/page-on-failure.ts</span></span>
18
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Any module under <code>agent/hooks/</code>, subfolders included, is a hook named by its path without the extension: <code>agent/hooks/audit/usage.ts</code> is <code>audit/usage</code>. <code>*.test.ts</code> and <code>*.spec.ts</code> files are skipped. The default export must be <code>defineHook(...)</code>, names can&#39;t contain <code>__</code>, and an empty <code>events</code> map skips the hook with a warning; <code>agent-sdk validate</code> reports all three. An extension mounts its hooks as <code>&lt;ns&gt;__&lt;name&gt;</code>, and <code>disableHook()</code> removes one (<a href="./extensions.html#adjust-a-mounted-extension">Adjust a mounted extension</a>).</p><p><code>agent-sdk init</code> scaffolds <code>agent/hooks/memory.ts</code>, which exports <code>memoryHook()</code> from <code>@cursor/july/memory</code> and journals every turn for later sessions to read. Delete the file to opt out.</p><h2 id="events-and-payloads" tabindex="-1">Events and payloads <a class="header-anchor" href="#events-and-payloads" aria-label="Permalink to &quot;Events and payloads&quot;">​</a></h2><p>Keys are event types from the <a href="./sessions.html#which-events-can-i-stream">event vocabulary</a>, or <code>&quot;*&quot;</code> for every event. A typed key narrows <code>event.data</code>; a <code>&quot;*&quot;</code> handler receives the union, so switch on <code>event.type</code>. Every event carries the stream envelope <code>{ type, index, sessionId, turnId?, at, data }</code>, with <code>turnId</code> set on turn-scoped events.</p><p>The payloads hooks read most often:</p><table tabindex="0"><thead><tr><th>Event</th><th><code>event.data</code></th></tr></thead><tbody><tr><td><code>message.received</code></td><td><code>{ text }</code></td></tr><tr><td><code>turn.completed</code></td><td><code>{ result?, usage?, cost? }</code>. <code>usage</code> has <code>inputTokens</code>, <code>outputTokens</code>, <code>cacheReadTokens</code>, <code>cacheWriteTokens</code>, and optional <code>reasoningTokens</code>. <code>cost</code> has <code>totalUsd</code> and the <code>model</code> it was priced against</td></tr><tr><td><code>turn.failed</code></td><td><code>{ message }</code></td></tr><tr><td><code>actions.requested</code></td><td><code>{ calls: [{ callId, toolName, args? }] }</code>. A call with <code>parentCallId</code> belongs to a subagent</td></tr><tr><td><code>action.result</code></td><td><code>{ callId, toolName, output?, isError, stubbed? }</code>. <code>stubbed</code> means a dry-run session answered a write without running it</td></tr></tbody></table><p>The types are <code>SessionEvent</code>, <code>SessionEventType</code>, and <code>HookContext</code>, exported from <code>@cursor/july</code>.</p><h2 id="handler-context" tabindex="-1">Handler context <a class="header-anchor" href="#handler-context" aria-label="Permalink to &quot;Handler context&quot;">​</a></h2><table tabindex="0"><thead><tr><th>Member</th><th>What it is</th></tr></thead><tbody><tr><td><code>ctx.session</code></td><td>Read-only session info: <code>id</code>, <code>channelId</code>, <code>mode</code> (<code>chat</code> or <code>task</code>), <code>purpose</code> (<code>live</code> or <code>eval</code>), <code>auth</code>, plus <code>title</code> and <code>sdkAgentId</code> when set</td></tr><tr><td><code>ctx.agent</code></td><td><code>{ name }</code> of the agent the event belongs to</td></tr><tr><td><code>ctx.channel</code></td><td><code>{ id, continuationToken }</code>. The token is <code>null</code> when the session can&#39;t take follow-ups</td></tr><tr><td><code>ctx.host.kv</code></td><td>Durable JSON, shared by every session of the agent; the <a href="./../storage.html#author-kv-ctx-host-kv">storage backend</a> decides whether it survives a hosted replace. Prefix keys with <code>ctx.session.id</code> for per-session state</td></tr><tr><td><code>ctx.host.files</code></td><td>Durable files, bound to this session. Pass <code>{ scope: &quot;deployment&quot; }</code> for agent-wide files</td></tr><tr><td><code>ctx.host.otel</code></td><td>Counters, histograms, and tags, attributed to this session</td></tr><tr><td><code>ctx.host.mcp</code>, <code>ctx.host.github</code>, <code>ctx.host.slack</code></td><td>The same shared clients tools get</td></tr><tr><td><code>ctx.host.reminders</code></td><td>Per-session <a href="./schedules.html">reminders</a>, the same API tools get</td></tr><tr><td><code>ctx.artifacts</code></td><td>Session-bound <a href="./artifacts.html">artifacts</a> facade: <code>tag</code> fills in <code>sessionId</code> and <code>turnId</code></td></tr><tr><td><code>ctx.stateRoot</code></td><td>Absolute path of the local state root. It resets when a hosted deployment is replaced; keep derived state in <code>kv</code> or <code>files</code></td></tr></tbody></table><h2 id="when-hooks-run" tabindex="-1">When hooks run <a class="header-anchor" href="#when-hooks-run" aria-label="Permalink to &quot;When hooks run&quot;">​</a></h2><p>A hook runs after the event is durably recorded. It never delays the model turn and never sees an event that wasn&#39;t recorded.</p><p>Within one session, events dispatch in order, one at a time: the channel&#39;s <code>events</code> handlers first, then each hook in discovery order. Sessions don&#39;t wait on each other.</p><p>Two consequences:</p><ul><li>A slow handler holds up the next event&#39;s handlers for that session, not the model. Keep handlers short and queue anything slow.</li><li>Hooks fire for eval sessions too. Check <code>ctx.session.purpose === &quot;eval&quot;</code> before metering or paging.</li></ul><p>Each event reaches a hook at most once. A restart doesn&#39;t replay the log into hooks, so a mirror needs no dedupe, and the event log rather than the hook&#39;s copy is the source of truth.</p><h2 id="hooks-channel-events-or-evals" tabindex="-1">Hooks, channel events, or evals? <a class="header-anchor" href="#hooks-channel-events-or-evals" aria-label="Permalink to &quot;Hooks, channel events, or evals?&quot;">​</a></h2><p>All of them consume the same stream, for different jobs:</p><table tabindex="0"><thead><tr><th></th><th>Hooks</th><th>Channel <code>events</code></th><th>Evals</th></tr></thead><tbody><tr><td>Scope</td><td>every session of the agent</td><td>sessions the channel owns</td><td>one test turn</td></tr><tr><td>Job</td><td>observe: audit, metrics, mirrors, derived state</td><td>deliver: replies back to the channel&#39;s surface</td><td>assert: gates over the trajectory</td></tr><tr><td>Context</td><td><code>ctx.host</code>, <code>ctx.artifacts</code>, session info</td><td><code>channel.state</code>, <code>setContinuationToken</code>, <code>ctx.host</code>, session info</td><td>the <code>t</code> assertion helpers</td></tr><tr><td>Can affect the run</td><td>no</td><td>yes, it owns the surface</td><td>n/a</td></tr><tr><td>Authored at</td><td><code>agent/hooks/*.ts</code></td><td>channel config</td><td><code>evals/**/*.eval.ts</code></td></tr></tbody></table><h2 id="when-not-to-use-a-hook" tabindex="-1">When not to use a hook <a class="header-anchor" href="#when-not-to-use-a-hook" aria-label="Permalink to &quot;When not to use a hook&quot;">​</a></h2><table tabindex="0"><thead><tr><th>You want to</th><th>Use instead</th></tr></thead><tbody><tr><td>Add context before the model runs</td><td>The channel&#39;s <code>send</code> message and <code>workspaceFiles</code>, <code>instructions.md</code>, skills, or <code>sandbox/workspace/</code> seed files</td></tr><tr><td>Reply on Slack, comment on a PR, or post any other delivery</td><td>The channel&#39;s <code>events</code> map, or the Slack and GitHub packs</td></tr><tr><td>Show PR progress (merge-box check, sticky banner)</td><td><code>githubChannel({ progress: { commitStatus, banner } })</code>; see <a href="./../guides/github.html#show-pr-progress">Show PR progress</a></td></tr><tr><td>Block, approve, or rewrite a tool call</td><td><a href="./tools.html#gate-a-tool-on-human-approval"><code>needsApproval</code></a> on the tool</td></tr><tr><td>Act on the final assistant text, or fail a bad turn</td><td><a href="./result.html"><code>defineResult</code></a></td></tr><tr><td>Gate a change on behavior</td><td><a href="./../evals.html">Evals</a></td></tr></tbody></table><h2 id="patterns" tabindex="-1">Patterns <a class="header-anchor" href="#patterns" aria-label="Permalink to &quot;Patterns&quot;">​</a></h2><p>Usage metering is the <a href="#author-a-hook">authoring example</a>. Three more:</p><h3 id="alert-on-failure" tabindex="-1">Alert on failure <a class="header-anchor" href="#alert-on-failure" aria-label="Permalink to &quot;Alert on failure&quot;">​</a></h3><p><code>turn.failed</code> carries the message, and <code>ctx.session.id</code> points at the trace. Skip interrupted turns; those are preemptions, not failures. Read secrets inside the handler: hosted deployments bind them after the process starts, so a module-scope read stays empty. Give the call a timeout, since a stalled request holds up later handlers on that session.</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:#6A737D;--shiki-dark:#6A737D;">// agent/hooks/page-on-failure.ts</span></span>
19
19
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { defineHook } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july/hooks&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
20
20
  <span class="line"></span>
21
21
  <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;"> defineHook</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
@@ -70,4 +70,4 @@ import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.BCISBCiQ.js";const c
70
70
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
71
71
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
72
72
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
73
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><h2 id="test-and-debug-a-hook" tabindex="-1">Test and debug a hook <a class="header-anchor" href="#test-and-debug-a-hook" aria-label="Permalink to &quot;Test and debug a hook&quot;">​</a></h2><p>A hook definition is a plain object, so a unit test calls <code>hook.events[&quot;turn.completed&quot;]</code> directly with an event and a stub <code>HookContext</code>. Discovery skips <code>*.test.ts</code>, so the test can live next to the hook.</p><p>At runtime:</p><ul><li><code>agent-sdk validate --dir .</code> reports discovery errors and the empty-handlers warning.</li><li><code>agent-sdk info --dir . --json</code> lists the loaded hooks under <code>agents[].hooks</code>.</li><li>Send a turn with <code>agent-sdk dev</code> or <code>agent-sdk run --dir . --message &quot;…&quot;</code> and watch the serve log for <code>hook &quot;&lt;name&gt;&quot; handler for &lt;event&gt; threw: …</code>. <code>run</code> prints that log on stderr. On hosting, read it with <a href="./cli.html#logs"><code>agent-sdk logs</code></a>.</li></ul><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="./result.html">Turn result</a>: fail a turn from <code>commit</code>, not from a hook</li><li><a href="./sessions.html">Sessions and streaming</a>: the event vocabulary hooks observe</li><li><a href="./../storage.html">Storage</a>: where <code>ctx.host.kv</code> and <code>ctx.host.files</code> live</li><li><a href="./../guides/opentelemetry.html">OpenTelemetry</a>: OTLP traces and metrics from the same event stream</li><li><a href="./../deployment.html#observability">Deployment</a>: runtime logs and export paths</li><li><a href="./channels.html#events">Channels</a>: the delivery-side counterpart</li><li><a href="./../ab.html">Live A/B metrics</a>: sticky variants over the same event stream</li></ul>`,45)])])}const E=e(n,[["render",h]]);export{c as __pageData,E as default};
73
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><h2 id="test-and-debug-a-hook" tabindex="-1">Test and debug a hook <a class="header-anchor" href="#test-and-debug-a-hook" aria-label="Permalink to &quot;Test and debug a hook&quot;">​</a></h2><p>A hook definition is a plain object, so a unit test calls <code>hook.events[&quot;turn.completed&quot;]</code> directly with an event and a stub <code>HookContext</code>. Discovery skips <code>*.test.ts</code>, so the test can live next to the hook.</p><p>At runtime:</p><ul><li><code>agent-sdk validate --dir .</code> reports discovery errors and the empty-handlers warning.</li><li><code>agent-sdk info --dir . --json</code> lists the loaded hooks under <code>agents[].hooks</code>.</li><li>Send a turn with <code>agent-sdk dev</code> or <code>agent-sdk run --dir . --message &quot;…&quot;</code> and watch the serve log for <code>hook &quot;&lt;name&gt;&quot; handler for &lt;event&gt; threw: …</code>. <code>run</code> prints that log on stderr. On hosting, read it with <a href="./cli.html#logs"><code>agent-sdk logs</code></a>.</li></ul><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="./result.html">Turn result</a>: fail a turn from <code>commit</code>, not from a hook</li><li><a href="./sessions.html">Sessions and streaming</a>: the event vocabulary hooks observe</li><li><a href="./../storage.html">Storage</a>: where <code>ctx.host.kv</code> and <code>ctx.host.files</code> live</li><li><a href="./../guides/opentelemetry.html">OpenTelemetry</a>: OTLP traces and metrics from the same event stream</li><li><a href="./../deployment.html#observability">Deployment</a>: runtime logs and export paths</li><li><a href="./channels.html#events">Channels</a>: the delivery-side counterpart</li></ul>`,45)])])}const E=e(n,[["render",h]]);export{c as __pageData,E as default};
@@ -1 +1 @@
1
- import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.BCISBCiQ.js";const c=JSON.parse('{"title":"Hooks","description":"Observe-only subscribers to the session event stream: audit logs, metrics, transcript mirrors, derived state.","frontmatter":{"title":"Hooks","description":"Observe-only subscribers to the session event stream: audit logs, metrics, transcript mirrors, derived state."},"headers":[],"relativePath":"reference/hooks.md","filePath":"reference/hooks.md"}'),n={name:"reference/hooks.md"};function h(o,s,l,d,r,p){return a(),t("div",null,[...s[0]||(s[0]=[i("",45)])])}const E=e(n,[["render",h]]);export{c as __pageData,E as default};
1
+ import{_ as e,c as a,o as t,ag as i}from"./chunks/framework.BCISBCiQ.js";const c=JSON.parse('{"title":"Hooks","description":"Observe-only subscribers to the session event stream: audit logs, metrics, transcript mirrors, derived state.","frontmatter":{"title":"Hooks","description":"Observe-only subscribers to the session event stream: audit logs, metrics, transcript mirrors, derived state."},"headers":[],"relativePath":"reference/hooks.md","filePath":"reference/hooks.md"}'),n={name:"reference/hooks.md"};function h(o,s,l,d,r,p){return t(),a("div",null,[...s[0]||(s[0]=[i("",45)])])}const E=e(n,[["render",h]]);export{c as __pageData,E as default};
@@ -8,4 +8,4 @@ import{_ as t,c as s,o,ag as a}from"./chunks/framework.BCISBCiQ.js";const p=JSON
8
8
  <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -H</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;content-type: application/json&#39;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> \\</span></span>
9
9
  <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -d</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;{&quot;input&quot;:{&quot;prUrl&quot;:&quot;https://github.com/acme/checkout/pull/42&quot;}}&#39;</span></span>
10
10
  <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># {&quot;ok&quot;:true,&quot;toolName&quot;:&quot;inspect_pr&quot;,&quot;callId&quot;:&quot;tool_inspect_pr_…&quot;,</span></span>
11
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># &quot;isError&quot;:false,&quot;result&quot;:{…},&quot;durationMs&quot;:12}</span></span></code></pre></div><p>It runs an authored server tool in-process: schema-validated, no model turn. An optional <code>&quot;sessionId&quot;</code> in the body runs it inside an existing session and records it on that session&#39;s stream (<code>409 session_busy</code> for a write-effect call while a turn runs; reads run alongside the turn). Agent-execution tools are rejected with <code>400</code>, and unknown tools with <code>404</code> and the list of available names. For the semantics, see <a href="./tools.html#call-a-tool-without-a-model-turn">Tools</a>.</p><p>An optional <code>&quot;continuationToken&quot;</code> (<code>&lt;channelId&gt;:&lt;key&gt;</code>, as <code>/v1/sessions</code> lists it; mutually exclusive with <code>sessionId</code>) addresses the session by continuation token instead; malformed tokens are rejected with <code>400 invalid_continuation_token</code>. For the semantics, see <a href="./tools.html#call-a-tool-without-a-model-turn">Tools</a>.</p><h2 id="discovery" tabindex="-1">Discovery <a class="header-anchor" href="#discovery" aria-label="Permalink to &quot;Discovery&quot;">​</a></h2><p>These read-only routes describe the running agent.</p><table tabindex="0"><thead><tr><th>Route</th><th>What it does</th></tr></thead><tbody><tr><td><code>GET /v1/info</code></td><td>The discovered surface: model, tools, skills, MCP connections, subagents, channels and routes (with schemas), schedules, hooks, A/B experiments, diagnostics</td></tr><tr><td><code>GET /v1/tools</code></td><td>The live tool catalog: authored server tools plus advertised MCP passthroughs under model-facing names, as light <code>{ name, title?, source? }</code> entries. <code>session</code> / <code>continuationToken</code> query parameters bind the listing to a session identity (advertised inventories can be tenant-scoped); a connection whose listing fails is skipped and reported in <code>connectionErrors</code></td></tr><tr><td><code>GET /v1/tools/:name</code></td><td>One catalog tool&#39;s full description: description, execution, <code>needsApproval</code>, <code>effect</code>, input and output schemas, source connection. Same session binding as the listing; unknown names get <code>404</code> with the available names</td></tr><tr><td><code>GET /v1/health</code></td><td>Per-agent liveness, no auth</td></tr><tr><td><code>GET /v1/logs?after=N</code></td><td>Recent server log lines, with a polling cursor</td></tr><tr><td><code>GET /v1/abs</code></td><td><a href="./../ab.html">Live A/B metrics</a>: per-session assignments and aggregate arm totals</td></tr></tbody></table><h2 id="artifacts" tabindex="-1">Artifacts <a class="header-anchor" href="#artifacts" aria-label="Permalink to &quot;Artifacts&quot;">​</a></h2><p>Two routes read durable artifacts tagged by <code>ctx.artifacts</code> or <code>tag_artifact</code>. See <a href="./artifacts.html">Artifacts</a>.</p><table tabindex="0"><thead><tr><th>Route</th><th>What it does</th></tr></thead><tbody><tr><td><code>GET /v1/artifacts</code></td><td>List artifacts as <code>{ artifacts }</code>, newest-updated first. Filter with <code>?kind=</code>, <code>?sessionId=</code>, and <code>?limit=</code> (a positive integer)</td></tr><tr><td><code>GET /v1/artifacts/:id/content</code></td><td>Download one artifact&#39;s file or blob payload. Served as an attachment, never rendered inline; <code>404</code> when the artifact is unknown or carries no content</td></tr></tbody></table><p>Session ownership applies the same way as <code>GET /v1/sessions</code>: under <code>serve --dev</code> on loopback (or <code>--allow-anonymous</code>) the list spans all principals, while bearer or custom channel auth keeps strict per-principal isolation.</p><h2 id="custom-channel-routes" tabindex="-1">Custom channel routes <a class="header-anchor" href="#custom-channel-routes" aria-label="Permalink to &quot;Custom channel routes&quot;">​</a></h2><p>Authored routes mount under <code>/v1/channels/&lt;id&gt;</code> with the methods, paths, and Zod schemas the channel declared (a <code>POST /&lt;slug&gt;/v1/channels/drive</code> route, say). Bodies are validated before handlers run (<code>400</code> on schema violations), and each channel&#39;s auth chain applies. The GitHub channel verifies <code>X-Hub-Signature-256</code> when a secret is configured. See <a href="./channels.html">Channels</a>.</p><h2 id="mcp-endpoint" tabindex="-1">MCP endpoint <a class="header-anchor" href="#mcp-endpoint" aria-label="Permalink to &quot;MCP endpoint&quot;">​</a></h2><p><code>/v1/mcp</code> serves the Model Context Protocol over streamable HTTP (stateless; POST carries the protocol, and GET/DELETE return spec-compliant 405s). The tools are <code>ask</code> (delegate a message, bounded waits), <code>check</code> (poll a running session), and <code>call_tool</code> (deterministic server-tool passthrough, present when the agent has server tools). The route runs the same auth chain as the session API. See <a href="./../guides/agent-to-agent.html">Agent-to-agent</a>.</p><p><code>/v1/mcp/tools</code> is a second stateless MCP endpoint exposing only the agent&#39;s deterministic server tools. Hosted cloud turns call back into it through the URL configured by <code>serve --cloud-tools-url</code>. Unlike <code>/v1/mcp</code>, it runs the CLI-level auth chain (loopback, bearer, or anonymous), not any authored channel auth.</p><h2 id="playground-eval-routes" tabindex="-1">Playground eval routes <a class="header-anchor" href="#playground-eval-routes" aria-label="Permalink to &quot;Playground eval routes&quot;">​</a></h2><p>The playground Evals tab and <code>agent-sdk eval --prod</code> / <code>--url</code> use these:</p><table tabindex="0"><thead><tr><th>Route</th><th>What it does</th></tr></thead><tbody><tr><td><code>GET /v1/dev/evals</code></td><td>List discovered eval datapoints and project config</td></tr><tr><td><code>GET /v1/dev/evals/runs</code></td><td>List recent run snapshots, newest first</td></tr><tr><td><code>POST /v1/dev/evals/runs</code></td><td>Start an eval run (<code>{filterIds?, tags?}</code>); <code>202</code> with a snapshot (<code>runId</code> is the Eval ID), <code>404</code> when nothing matches, <code>409</code> when one is running</td></tr><tr><td><code>GET /v1/dev/evals/runs/:runId</code></td><td>Poll a run&#39;s progress</td></tr><tr><td><code>POST /v1/dev/evals/runs/:runId/cancel</code></td><td>Cancel a running batch; <code>200</code> with snapshot, <code>404</code> unknown, <code>409</code> when not running</td></tr></tbody></table><p>Eval runs are asynchronous. Poll the run route for case progress and the final <code>completed</code> or <code>failed</code> status. Batch errors appear on the snapshot returned by the poll. Entries within <code>filterIds</code> and <code>tags</code> use OR semantics. When both fields are present, a case must match one entry from each field. Listed runs persist across restarts when storage is configured; see <a href="./../storage.html#eval-and-a-b-tables">Storage</a>. Otherwise they are process-memory only.</p><h2 id="dev-mode-routes" tabindex="-1">Dev-mode routes <a class="header-anchor" href="#dev-mode-routes" aria-label="Permalink to &quot;Dev-mode routes&quot;">​</a></h2><p>These routes exist only under <code>serve --dev</code>.</p><table tabindex="0"><thead><tr><th>Route</th><th>What it does</th></tr></thead><tbody><tr><td><code>POST /v1/dev/schedules/:scheduleId</code></td><td>Dispatch a schedule by hand, exactly once. Returns <code>{scheduleId, sessionIds}</code></td></tr><tr><td><code>GET /v1/dev/reminders</code></td><td>List reminders</td></tr><tr><td><code>POST /v1/dev/reminders/:reminderId</code></td><td>Fire a reminder by hand</td></tr></tbody></table><p>Schedules and reminders never fire automatically in dev mode. These routes are the only way they run, which keeps iteration deterministic.</p><h2 id="playground-assets" tabindex="-1">Playground assets <a class="header-anchor" href="#playground-assets" aria-label="Permalink to &quot;Playground assets&quot;">​</a></h2><p><code>GET /playground</code> and <code>GET /playground/assets/:file</code> serve the playground (omitted with <code>--no-playground</code>). It calls the JSON API above and has no privileged surface.</p><h2 id="status-codes" tabindex="-1">Status codes <a class="header-anchor" href="#status-codes" aria-label="Permalink to &quot;Status codes&quot;">​</a></h2><p>Error responses use a small, consistent set of status codes.</p><table tabindex="0"><thead><tr><th>Code</th><th>Meaning here</th></tr></thead><tbody><tr><td><code>400</code></td><td>Schema-invalid body or query, agent-execution tool called on the host, malformed request</td></tr><tr><td><code>401</code></td><td>No auth policy admitted the request</td></tr><tr><td><code>403</code></td><td>Authenticated, but not the session owner</td></tr><tr><td><code>404</code></td><td>Unknown session, tool, schedule, reminder, or eval run; no eval datapoints match a run request</td></tr><tr><td><code>405</code></td><td>Wrong method (GET on the MCP endpoint, say)</td></tr><tr><td><code>409</code></td><td>Stale continuation token, a busy session-bound tool call, a non-followable task session, or an eval run already in progress</td></tr><tr><td><code>202</code></td><td>Accepted for background work (GitHub <code>{ task }</code> hooks, eval runs)</td></tr></tbody></table><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="./sessions.html">Sessions and streaming</a>: the handles and events these routes traffic in</li><li><a href="./channels.html">Channels</a>: authoring your own routes</li><li><a href="./../deployment.html">Deployment</a>: auth on real hosts</li></ul>`,62)])])}const k=t(n,[["render",d]]);export{p as __pageData,k as default};
11
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># &quot;isError&quot;:false,&quot;result&quot;:{…},&quot;durationMs&quot;:12}</span></span></code></pre></div><p>It runs an authored server tool in-process: schema-validated, no model turn. An optional <code>&quot;sessionId&quot;</code> in the body runs it inside an existing session and records it on that session&#39;s stream (<code>409 session_busy</code> for a write-effect call while a turn runs; reads run alongside the turn). Agent-execution tools are rejected with <code>400</code>, and unknown tools with <code>404</code> and the list of available names. For the semantics, see <a href="./tools.html#call-a-tool-without-a-model-turn">Tools</a>.</p><p>An optional <code>&quot;continuationToken&quot;</code> (<code>&lt;channelId&gt;:&lt;key&gt;</code>, as <code>/v1/sessions</code> lists it; mutually exclusive with <code>sessionId</code>) addresses the session by continuation token instead; malformed tokens are rejected with <code>400 invalid_continuation_token</code>. For the semantics, see <a href="./tools.html#call-a-tool-without-a-model-turn">Tools</a>.</p><h2 id="discovery" tabindex="-1">Discovery <a class="header-anchor" href="#discovery" aria-label="Permalink to &quot;Discovery&quot;">​</a></h2><p>These read-only routes describe the running agent.</p><table tabindex="0"><thead><tr><th>Route</th><th>What it does</th></tr></thead><tbody><tr><td><code>GET /v1/info</code></td><td>The discovered surface: model, tools, skills, MCP connections, subagents, channels and routes (with schemas), schedules, hooks, diagnostics</td></tr><tr><td><code>GET /v1/tools</code></td><td>The live tool catalog: authored server tools plus advertised MCP passthroughs under model-facing names, as light <code>{ name, title?, source? }</code> entries. <code>session</code> / <code>continuationToken</code> query parameters bind the listing to a session identity (advertised inventories can be tenant-scoped); a connection whose listing fails is skipped and reported in <code>connectionErrors</code></td></tr><tr><td><code>GET /v1/tools/:name</code></td><td>One catalog tool&#39;s full description: description, execution, <code>needsApproval</code>, <code>effect</code>, input and output schemas, source connection. Same session binding as the listing; unknown names get <code>404</code> with the available names</td></tr><tr><td><code>GET /v1/health</code></td><td>Per-agent liveness, no auth</td></tr><tr><td><code>GET /v1/logs?after=N</code></td><td>Recent server log lines, with a polling cursor</td></tr></tbody></table><h2 id="artifacts" tabindex="-1">Artifacts <a class="header-anchor" href="#artifacts" aria-label="Permalink to &quot;Artifacts&quot;">​</a></h2><p>Two routes read durable artifacts tagged by <code>ctx.artifacts</code> or <code>tag_artifact</code>. See <a href="./artifacts.html">Artifacts</a>.</p><table tabindex="0"><thead><tr><th>Route</th><th>What it does</th></tr></thead><tbody><tr><td><code>GET /v1/artifacts</code></td><td>List artifacts as <code>{ artifacts }</code>, newest-updated first. Filter with <code>?kind=</code>, <code>?sessionId=</code>, and <code>?limit=</code> (a positive integer)</td></tr><tr><td><code>GET /v1/artifacts/:id/content</code></td><td>Download one artifact&#39;s file or blob payload. Served as an attachment, never rendered inline; <code>404</code> when the artifact is unknown or carries no content</td></tr></tbody></table><p>Session ownership applies the same way as <code>GET /v1/sessions</code>: under <code>serve --dev</code> on loopback (or <code>--allow-anonymous</code>) the list spans all principals, while bearer or custom channel auth keeps strict per-principal isolation.</p><h2 id="custom-channel-routes" tabindex="-1">Custom channel routes <a class="header-anchor" href="#custom-channel-routes" aria-label="Permalink to &quot;Custom channel routes&quot;">​</a></h2><p>Authored routes mount under <code>/v1/channels/&lt;id&gt;</code> with the methods, paths, and Zod schemas the channel declared (a <code>POST /&lt;slug&gt;/v1/channels/drive</code> route, say). Bodies are validated before handlers run (<code>400</code> on schema violations), and each channel&#39;s auth chain applies. The GitHub channel verifies <code>X-Hub-Signature-256</code> when a secret is configured. See <a href="./channels.html">Channels</a>.</p><h2 id="mcp-endpoint" tabindex="-1">MCP endpoint <a class="header-anchor" href="#mcp-endpoint" aria-label="Permalink to &quot;MCP endpoint&quot;">​</a></h2><p><code>/v1/mcp</code> serves the Model Context Protocol over streamable HTTP (stateless; POST carries the protocol, and GET/DELETE return spec-compliant 405s). The tools are <code>ask</code> (delegate a message, bounded waits), <code>check</code> (poll a running session), and <code>call_tool</code> (deterministic server-tool passthrough, present when the agent has server tools). The route runs the same auth chain as the session API. See <a href="./../guides/agent-to-agent.html">Agent-to-agent</a>.</p><p><code>/v1/mcp/tools</code> is a second stateless MCP endpoint exposing only the agent&#39;s deterministic server tools. Hosted cloud turns call back into it through the URL configured by <code>serve --cloud-tools-url</code>. Unlike <code>/v1/mcp</code>, it runs the CLI-level auth chain (loopback, bearer, or anonymous), not any authored channel auth.</p><h2 id="playground-eval-routes" tabindex="-1">Playground eval routes <a class="header-anchor" href="#playground-eval-routes" aria-label="Permalink to &quot;Playground eval routes&quot;">​</a></h2><p>The playground Evals tab and <code>agent-sdk eval --prod</code> / <code>--url</code> use these:</p><table tabindex="0"><thead><tr><th>Route</th><th>What it does</th></tr></thead><tbody><tr><td><code>GET /v1/dev/evals</code></td><td>List discovered eval datapoints and project config</td></tr><tr><td><code>GET /v1/dev/evals/runs</code></td><td>List recent run snapshots, newest first</td></tr><tr><td><code>POST /v1/dev/evals/runs</code></td><td>Start an eval run (<code>{filterIds?, tags?}</code>); <code>202</code> with a snapshot (<code>runId</code> is the Eval ID), <code>404</code> when nothing matches, <code>409</code> when one is running</td></tr><tr><td><code>GET /v1/dev/evals/runs/:runId</code></td><td>Poll a run&#39;s progress</td></tr><tr><td><code>POST /v1/dev/evals/runs/:runId/cancel</code></td><td>Cancel a running batch; <code>200</code> with snapshot, <code>404</code> unknown, <code>409</code> when not running</td></tr></tbody></table><p>Eval runs are asynchronous. Poll the run route for case progress and the final <code>completed</code> or <code>failed</code> status. Batch errors appear on the snapshot returned by the poll. Entries within <code>filterIds</code> and <code>tags</code> use OR semantics. When both fields are present, a case must match one entry from each field. Listed runs persist across restarts when storage is configured; see <a href="./../storage.html#eval-table">Storage</a>. Otherwise they are process-memory only.</p><h2 id="dev-mode-routes" tabindex="-1">Dev-mode routes <a class="header-anchor" href="#dev-mode-routes" aria-label="Permalink to &quot;Dev-mode routes&quot;">​</a></h2><p>These routes exist only under <code>serve --dev</code>.</p><table tabindex="0"><thead><tr><th>Route</th><th>What it does</th></tr></thead><tbody><tr><td><code>POST /v1/dev/schedules/:scheduleId</code></td><td>Dispatch a schedule by hand, exactly once. Returns <code>{scheduleId, sessionIds}</code></td></tr><tr><td><code>GET /v1/dev/reminders</code></td><td>List reminders</td></tr><tr><td><code>POST /v1/dev/reminders/:reminderId</code></td><td>Fire a reminder by hand</td></tr></tbody></table><p>Schedules and reminders never fire automatically in dev mode. These routes are the only way they run, which keeps iteration deterministic.</p><h2 id="playground-assets" tabindex="-1">Playground assets <a class="header-anchor" href="#playground-assets" aria-label="Permalink to &quot;Playground assets&quot;">​</a></h2><p><code>GET /playground</code> and <code>GET /playground/assets/:file</code> serve the playground (omitted with <code>--no-playground</code>). It calls the JSON API above and has no privileged surface.</p><h2 id="status-codes" tabindex="-1">Status codes <a class="header-anchor" href="#status-codes" aria-label="Permalink to &quot;Status codes&quot;">​</a></h2><p>Error responses use a small, consistent set of status codes.</p><table tabindex="0"><thead><tr><th>Code</th><th>Meaning here</th></tr></thead><tbody><tr><td><code>400</code></td><td>Schema-invalid body or query, agent-execution tool called on the host, malformed request</td></tr><tr><td><code>401</code></td><td>No auth policy admitted the request</td></tr><tr><td><code>403</code></td><td>Authenticated, but not the session owner</td></tr><tr><td><code>404</code></td><td>Unknown session, tool, schedule, reminder, or eval run; no eval datapoints match a run request</td></tr><tr><td><code>405</code></td><td>Wrong method (GET on the MCP endpoint, say)</td></tr><tr><td><code>409</code></td><td>Stale continuation token, a busy session-bound tool call, a non-followable task session, or an eval run already in progress</td></tr><tr><td><code>202</code></td><td>Accepted for background work (GitHub <code>{ task }</code> hooks, eval runs)</td></tr></tbody></table><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="./sessions.html">Sessions and streaming</a>: the handles and events these routes traffic in</li><li><a href="./channels.html">Channels</a>: authoring your own routes</li><li><a href="./../deployment.html">Deployment</a>: auth on real hosts</li></ul>`,62)])])}const k=t(n,[["render",d]]);export{p as __pageData,k as default};
@@ -1 +1 @@
1
- import{_ as t,c as o,o as a,ag as s}from"./chunks/framework.BCISBCiQ.js";const u=JSON.parse('{"title":"Playground","description":"The built-in web UI: chat with streaming, Try buttons and slash commands, session replay, approvals, and dev-mode dispatch.","frontmatter":{"title":"Playground","description":"The built-in web UI: chat with streaming, Try buttons and slash commands, session replay, approvals, and dev-mode dispatch."},"headers":[],"relativePath":"reference/playground.md","filePath":"reference/playground.md"}'),n={name:"reference/playground.md"};function r(l,e,d,i,c,h){return a(),o("div",null,[...e[0]||(e[0]=[s('<h1 id="playground" tabindex="-1">Playground <a class="header-anchor" href="#playground" aria-label="Permalink to &quot;Playground&quot;">​</a></h1><p>Every served agent ships with a web playground at <code>http://127.0.0.1:3000/&lt;slug&gt;/playground</code> (or <code>/playground</code> in single mode). Anything you can do there you can also do with curl.</p><h2 id="what-it-does" tabindex="-1">What it does <a class="header-anchor" href="#what-it-does" aria-label="Permalink to &quot;What it does&quot;">​</a></h2><p>Use the playground to chat, try channel routes, and inspect sessions.</p><ul><li><strong>Chat</strong> with the agent. Text and reasoning stream live, and tool calls appear inline with their arguments, output, and error state.</li><li><strong>Slash commands</strong>: custom channel routes become composer commands (a <code>drive</code> route becomes <code>/drive &lt;pr-url&gt;</code>), with <code>/help</code> and autocomplete.</li><li><strong>Try</strong> any channel route from the Agent surface. The modal remembers your last body per endpoint and has Copy curl, and a successful Try opens the created session.</li><li><strong>Sessions</strong>: browse the sessions you own (chat, custom-channel, schedule tasks) and replay their event streams. In <code>--dev</code> on loopback, or with <code>--allow-anonymous</code>, the list includes every principal. Search by session ID to filter the list, or press Enter to open an ID directly. &quot;Open trace&quot; renders a saved event stream.</li><li><strong>Approvals</strong>: parked <code>needsApproval</code> tool calls render Approve / Deny buttons.</li><li><strong>Evals</strong>: list and run filesystem evals from the browser (backed by <code>/v1/dev/evals</code>). Schedule hand-dispatch still requires <code>--dev</code>.</li><li><strong>The surface</strong>: inspect the discovered tools, skills, subagents, MCP connections, channels, and hooks.</li><li><strong>Custom tool chips</strong>: drop <code>agent/playground/tools/&lt;toolName&gt;.tsx</code> to change how that tool renders. Chips compile from the agent tree; an <a href="./extensions.html">extension</a> cannot contribute them.</li><li><strong>Raw events pane</strong>: flip it on to inspect the event stream.</li><li><strong>Logs tab</strong>: recent server log lines, polled from <code>GET /v1/logs</code>.</li><li><strong>A/Bs tab</strong>: per-session and aggregate <a href="./../ab.html">live A/B metrics</a> from <code>GET /v1/abs</code>.</li></ul><p>In multi-agent mode each agent has its own playground at <code>/&lt;slug&gt;/playground</code>, and <code>/</code> is an index of them all.</p><h2 id="share-it-beyond-localhost" tabindex="-1">Share it beyond localhost <a class="header-anchor" href="#share-it-beyond-localhost" aria-label="Permalink to &quot;Share it beyond localhost&quot;">​</a></h2><p>The default <code>localDevStrict()</code> auth admits direct loopback calls only and rejects proxy-forwarding headers, so a tunnel or LAN address won&#39;t work until you pass <code>--bearer-token &lt;secret&gt;</code> (or <code>serve(dir, { authToken })</code>). Open the playground on the remote device and paste the token into the token field in the navbar. <code>--allow-anonymous</code> is the demo-only alternative for trusted networks.</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="./http-api.html">HTTP API</a>: the HTTP surface the playground uses</li><li><a href="./sessions.html">Sessions and streaming</a>: the streams it renders</li><li><a href="./../guides/human-in-the-loop.html">Human-in-the-loop</a>: the approval buttons in context</li><li><a href="./../ab.html">Live A/B metrics</a>: the assignments and results in the A/Bs tab</li></ul>',11)])])}const g=t(n,[["render",r]]);export{u as __pageData,g as default};
1
+ import{_ as t,c as o,o as a,ag as n}from"./chunks/framework.BCISBCiQ.js";const u=JSON.parse('{"title":"Playground","description":"The built-in web UI: chat with streaming, Try buttons and slash commands, session replay, approvals, and dev-mode dispatch.","frontmatter":{"title":"Playground","description":"The built-in web UI: chat with streaming, Try buttons and slash commands, session replay, approvals, and dev-mode dispatch."},"headers":[],"relativePath":"reference/playground.md","filePath":"reference/playground.md"}'),s={name:"reference/playground.md"};function r(l,e,d,i,c,h){return a(),o("div",null,[...e[0]||(e[0]=[n('<h1 id="playground" tabindex="-1">Playground <a class="header-anchor" href="#playground" aria-label="Permalink to &quot;Playground&quot;">​</a></h1><p>Every served agent ships with a web playground at <code>http://127.0.0.1:3000/&lt;slug&gt;/playground</code> (or <code>/playground</code> in single mode). Anything you can do there you can also do with curl.</p><h2 id="what-it-does" tabindex="-1">What it does <a class="header-anchor" href="#what-it-does" aria-label="Permalink to &quot;What it does&quot;">​</a></h2><p>Use the playground to chat, try channel routes, and inspect sessions.</p><ul><li><strong>Chat</strong> with the agent. Text and reasoning stream live, and tool calls appear inline with their arguments, output, and error state.</li><li><strong>Slash commands</strong>: custom channel routes become composer commands (a <code>drive</code> route becomes <code>/drive &lt;pr-url&gt;</code>), with <code>/help</code> and autocomplete.</li><li><strong>Try</strong> any channel route from the Agent surface. The modal remembers your last body per endpoint and has Copy curl, and a successful Try opens the created session.</li><li><strong>Sessions</strong>: browse the sessions you own (chat, custom-channel, schedule tasks) and replay their event streams. In <code>--dev</code> on loopback, or with <code>--allow-anonymous</code>, the list includes every principal. Search by session ID to filter the list, or press Enter to open an ID directly. &quot;Open trace&quot; renders a saved event stream.</li><li><strong>Approvals</strong>: parked <code>needsApproval</code> tool calls render Approve / Deny buttons.</li><li><strong>Evals</strong>: list and run filesystem evals from the browser (backed by <code>/v1/dev/evals</code>). Schedule hand-dispatch still requires <code>--dev</code>.</li><li><strong>The surface</strong>: inspect the discovered tools, skills, subagents, MCP connections, channels, and hooks.</li><li><strong>Custom tool chips</strong>: drop <code>agent/playground/tools/&lt;toolName&gt;.tsx</code> to change how that tool renders. Chips compile from the agent tree; an <a href="./extensions.html">extension</a> cannot contribute them.</li><li><strong>Raw events pane</strong>: flip it on to inspect the event stream.</li><li><strong>Logs tab</strong>: recent server log lines, polled from <code>GET /v1/logs</code>.</li></ul><p>In multi-agent mode each agent has its own playground at <code>/&lt;slug&gt;/playground</code>, and <code>/</code> is an index of them all.</p><h2 id="share-it-beyond-localhost" tabindex="-1">Share it beyond localhost <a class="header-anchor" href="#share-it-beyond-localhost" aria-label="Permalink to &quot;Share it beyond localhost&quot;">​</a></h2><p>The default <code>localDevStrict()</code> auth admits direct loopback calls only and rejects proxy-forwarding headers, so a tunnel or LAN address won&#39;t work until you pass <code>--bearer-token &lt;secret&gt;</code> (or <code>serve(dir, { authToken })</code>). Open the playground on the remote device and paste the token into the token field in the navbar. <code>--allow-anonymous</code> is the demo-only alternative for trusted networks.</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="./http-api.html">HTTP API</a>: the HTTP surface the playground uses</li><li><a href="./sessions.html">Sessions and streaming</a>: the streams it renders</li><li><a href="./../guides/human-in-the-loop.html">Human-in-the-loop</a>: the approval buttons in context</li></ul>',11)])])}const g=t(s,[["render",r]]);export{u as __pageData,g as default};
@@ -1 +1 @@
1
- import{_ as t,c as o,o as a,ag as s}from"./chunks/framework.BCISBCiQ.js";const u=JSON.parse('{"title":"Playground","description":"The built-in web UI: chat with streaming, Try buttons and slash commands, session replay, approvals, and dev-mode dispatch.","frontmatter":{"title":"Playground","description":"The built-in web UI: chat with streaming, Try buttons and slash commands, session replay, approvals, and dev-mode dispatch."},"headers":[],"relativePath":"reference/playground.md","filePath":"reference/playground.md"}'),n={name:"reference/playground.md"};function r(l,e,d,i,c,h){return a(),o("div",null,[...e[0]||(e[0]=[s("",11)])])}const g=t(n,[["render",r]]);export{u as __pageData,g as default};
1
+ import{_ as t,c as o,o as a,ag as n}from"./chunks/framework.BCISBCiQ.js";const u=JSON.parse('{"title":"Playground","description":"The built-in web UI: chat with streaming, Try buttons and slash commands, session replay, approvals, and dev-mode dispatch.","frontmatter":{"title":"Playground","description":"The built-in web UI: chat with streaming, Try buttons and slash commands, session replay, approvals, and dev-mode dispatch."},"headers":[],"relativePath":"reference/playground.md","filePath":"reference/playground.md"}'),s={name:"reference/playground.md"};function r(l,e,d,i,c,h){return a(),o("div",null,[...e[0]||(e[0]=[n("",11)])])}const g=t(s,[["render",r]]);export{u as __pageData,g as default};
@@ -1,4 +1,4 @@
1
- import{_ as t,c as s,o as a,ag as d}from"./chunks/framework.BCISBCiQ.js";const g=JSON.parse('{"title":"Project layout","description":"The folder structure under agent/ and the path-derived naming rule.","frontmatter":{"title":"Project layout","description":"The folder structure under agent/ and the path-derived naming rule."},"headers":[],"relativePath":"reference/project-layout.md","filePath":"reference/project-layout.md"}'),o={name:"reference/project-layout.md"};function n(r,e,i,c,l,h){return a(),s("div",null,[...e[0]||(e[0]=[d(`<h1 id="project-layout" tabindex="-1">Project layout <a class="header-anchor" href="#project-layout" aria-label="Permalink to &quot;Project layout&quot;">​</a></h1><p>The Agent SDK builds an agent by walking the filesystem under <code>agent/</code>. Each folder has a defined purpose. The path a file lands in determines how the Agent SDK loads it.</p><h2 id="folder-structure" tabindex="-1">Folder structure <a class="header-anchor" href="#folder-structure" aria-label="Permalink to &quot;Folder structure&quot;">​</a></h2><p>For the capabilities below, identity usually comes from the path. A/B experiments can override their file-derived name.</p><table tabindex="0"><thead><tr><th>Path</th><th>Resolves to</th></tr></thead><tbody><tr><td><code>agent/tools/approve_pr.ts</code></td><td>tool <code>approve_pr</code></td></tr><tr><td><code>agent/mcp-connections/linear.ts</code></td><td>MCP connection <code>linear</code> (model + host)</td></tr><tr><td><code>agent/host-connections/anytool.ts</code></td><td>Host MCP connection <code>anytool</code> (host + <code>mcp oauth</code> only)</td></tr><tr><td><code>agent/skills/pr-review.md</code></td><td>skill <code>pr-review</code></td></tr><tr><td><code>agent/subagents/reviewer/</code></td><td>subagent <code>reviewer</code></td></tr><tr><td><code>agent/extensions/ci.ts</code></td><td>extension mount <code>ci</code>; its contributions become <code>ci__&lt;name&gt;</code></td></tr><tr><td><code>agent/extensions/notion.ts</code></td><td>Cursor plugin mount <code>notion</code> (<code>cursorPlugin</code>); its skills, agents, and MCP servers become <code>notion__&lt;name&gt;</code></td></tr><tr><td><code>agent/channels/drive.ts</code></td><td>channel <code>drive</code>, routes under <code>/v1/channels/drive</code></td></tr><tr><td><code>agent/ab.ts</code></td><td>A/B experiment <code>ab</code> unless <code>name</code> overrides it</td></tr><tr><td><code>agent/ab/concise.ts</code></td><td>A/B experiment <code>concise</code> unless <code>name</code> overrides it</td></tr></tbody></table><p>The root agent takes its name from <code>package.json</code> <code>name</code>, falling back to the directory name. When serving multiple agents, the slug is the directory name and must match <code>[A-Za-z0-9][A-Za-z0-9_-]*</code> (and not the reserved <code>v1</code>, <code>playground</code>, or <code>docs</code> segments).</p><h2 id="project-overview" tabindex="-1">Project overview <a class="header-anchor" href="#project-overview" aria-label="Permalink to &quot;Project overview&quot;">​</a></h2><p>Most projects start with this shape.</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>my-agent/</span></span>
1
+ import{_ as t,c as s,o as a,ag as o}from"./chunks/framework.BCISBCiQ.js";const g=JSON.parse('{"title":"Project layout","description":"The folder structure under agent/ and the path-derived naming rule.","frontmatter":{"title":"Project layout","description":"The folder structure under agent/ and the path-derived naming rule."},"headers":[],"relativePath":"reference/project-layout.md","filePath":"reference/project-layout.md"}'),d={name:"reference/project-layout.md"};function n(r,e,i,c,l,h){return a(),s("div",null,[...e[0]||(e[0]=[o(`<h1 id="project-layout" tabindex="-1">Project layout <a class="header-anchor" href="#project-layout" aria-label="Permalink to &quot;Project layout&quot;">​</a></h1><p>The Agent SDK builds an agent by walking the filesystem under <code>agent/</code>. Each folder has a defined purpose. The path a file lands in determines how the Agent SDK loads it.</p><h2 id="folder-structure" tabindex="-1">Folder structure <a class="header-anchor" href="#folder-structure" aria-label="Permalink to &quot;Folder structure&quot;">​</a></h2><p>For the capabilities below, identity comes from the path.</p><table tabindex="0"><thead><tr><th>Path</th><th>Resolves to</th></tr></thead><tbody><tr><td><code>agent/tools/approve_pr.ts</code></td><td>tool <code>approve_pr</code></td></tr><tr><td><code>agent/mcp-connections/linear.ts</code></td><td>MCP connection <code>linear</code> (model + host)</td></tr><tr><td><code>agent/host-connections/anytool.ts</code></td><td>Host MCP connection <code>anytool</code> (host + <code>mcp oauth</code> only)</td></tr><tr><td><code>agent/skills/pr-review.md</code></td><td>skill <code>pr-review</code></td></tr><tr><td><code>agent/subagents/reviewer/</code></td><td>subagent <code>reviewer</code></td></tr><tr><td><code>agent/extensions/ci.ts</code></td><td>extension mount <code>ci</code>; its contributions become <code>ci__&lt;name&gt;</code></td></tr><tr><td><code>agent/extensions/notion.ts</code></td><td>Cursor plugin mount <code>notion</code> (<code>cursorPlugin</code>); its skills, agents, and MCP servers become <code>notion__&lt;name&gt;</code></td></tr><tr><td><code>agent/channels/drive.ts</code></td><td>channel <code>drive</code>, routes under <code>/v1/channels/drive</code></td></tr></tbody></table><p>The root agent takes its name from <code>package.json</code> <code>name</code>, falling back to the directory name. When serving multiple agents, the slug is the directory name and must match <code>[A-Za-z0-9][A-Za-z0-9_-]*</code> (and not the reserved <code>v1</code>, <code>playground</code>, or <code>docs</code> segments).</p><h2 id="project-overview" tabindex="-1">Project overview <a class="header-anchor" href="#project-overview" aria-label="Permalink to &quot;Project overview&quot;">​</a></h2><p>Most projects start with this shape.</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>my-agent/</span></span>
2
2
  <span class="line"><span>├── package.json</span></span>
3
3
  <span class="line"><span>├── agent/</span></span>
4
4
  <span class="line"><span>│ ├── agent.ts # runtime config (model, runtime, cloud/local)</span></span>
@@ -14,6 +14,6 @@ import{_ as t,c as s,o as a,ag as d}from"./chunks/framework.BCISBCiQ.js";const g
14
14
  <span class="line"><span>│ └── channels/</span></span>
15
15
  <span class="line"><span>│ └── github.ts # messages and external events</span></span>
16
16
  <span class="line"><span>└── evals/</span></span>
17
- <span class="line"><span> └── readiness.eval.ts # regression cases</span></span></code></pre></div><p>Evals live in <code>evals/</code> at the project root, a sibling of <code>agent/</code>, never inside it. <code>agent/evals/</code> is silently ignored. See <a href="./../evals.html">Evals</a>.</p><h2 id="folder-reference" tabindex="-1">Folder reference <a class="header-anchor" href="#folder-reference" aria-label="Permalink to &quot;Folder reference&quot;">​</a></h2><p>Each path maps to a capability and a reference page.</p><table tabindex="0"><thead><tr><th>Path</th><th>What it is</th><th>Reference</th></tr></thead><tbody><tr><td><code>agent/agent.ts</code></td><td><code>defineAgent({ model?, runtime?, cloud?, local? })</code>; the model defaults to <code>grok-4.5</code> with <code>effort=high</code>, <code>fast=true</code></td><td><a href="./agent-config.html">Agent config</a></td></tr><tr><td><code>agent/instructions.md</code></td><td>Always-on system prompt, required on the root agent (<code>.ts</code> and directory forms exist)</td><td><a href="./instructions.html">Instructions</a></td></tr><tr><td><code>agent/tools/&lt;name&gt;.ts</code></td><td>One typed tool; filename = tool name. <code>execution: &quot;server&quot;</code> (in-process, default) or <code>&quot;agent&quot;</code> (a script that runs where the agent runs)</td><td><a href="./tools.html">Tools</a></td></tr><tr><td><code>agent/skills/*</code></td><td>SKILL.md-convention procedures, loaded on demand</td><td><a href="./skills.html">Skills</a></td></tr><tr><td><code>agent/mcp-connections/&lt;name&gt;.ts</code></td><td>MCP servers, available to the model, to server tools (<code>ctx.host.mcp</code>), and to channel/schedule handlers (<code>args.host.mcp</code>)</td><td><a href="./connections.html">MCP connections</a></td></tr><tr><td><code>agent/host-connections/&lt;name&gt;.ts</code></td><td>Privileged MCP servers for <code>ctx.host.mcp</code> and <code>mcp oauth</code>. The model never sees them.</td><td><a href="./connections.html">MCP connections</a></td></tr><tr><td><code>agent/subagents/&lt;id&gt;/</code></td><td>Child agent directory; <code>description</code> required</td><td><a href="./subagents.html">Subagents</a></td></tr><tr><td><code>agent/extensions/&lt;ns&gt;.ts</code> or <code>agent/extensions/&lt;ns&gt;/</code></td><td>A mounted extension or Cursor plugin; its contributions become <code>&lt;ns&gt;__&lt;name&gt;</code></td><td><a href="./extensions.html">Extensions</a></td></tr><tr><td><code>agent/channels/*.ts</code></td><td>HTTP surfaces beyond the built-in session API; <code>slack.ts</code> and <code>github.ts</code> use the platform packs</td><td><a href="./channels.html">Channels</a></td></tr><tr><td><code>agent/hooks/*.ts</code></td><td>Observe-only event subscribers, never fatal</td><td><a href="./hooks.html">Hooks</a></td></tr><tr><td><code>agent/otel.ts</code></td><td><code>defineOtel</code> OTLP export (traces, metrics, optional logs)</td><td><a href="./../guides/opentelemetry.html">OpenTelemetry</a></td></tr><tr><td><code>agent/ab.ts</code>, <code>agent/ab/*.ts</code></td><td><code>defineAB</code> experiments with sticky variants and live metrics</td><td><a href="./../ab.html">Live A/B metrics</a></td></tr><tr><td><code>agent/ab.config.ts</code></td><td><code>defineABConfig</code> shared A/B settings</td><td><a href="./../ab.html">Live A/B metrics</a></td></tr><tr><td><code>agent/storage.ts</code></td><td><code>defineStorage</code> backend for the durable <code>host.kv</code> / <code>host.files</code> APIs</td><td><a href="./../storage.html">Storage</a></td></tr><tr><td><code>agent/artifacts.ts</code></td><td><code>defineArtifacts</code> kinds, the <code>tag_artifact</code> opt-in, and retention</td><td><a href="./artifacts.html">Artifacts</a></td></tr><tr><td><code>agent/result.ts</code></td><td><code>defineResult</code> host <code>commit</code> on the final assistant text</td><td><a href="./result.html">Turn result</a></td></tr><tr><td><code>agent/schedules/*</code></td><td>Cron-driven runs (UTC, 5-field; never auto-fire under <code>--dev</code>)</td><td><a href="./schedules.html">Schedules</a></td></tr><tr><td><code>agent/sandbox/workspace/**</code></td><td>Seed files copied into each local session workspace</td><td><a href="./sessions.html#what-goes-into-a-local-session-workspace">Sessions</a></td></tr><tr><td><code>agent/playground/</code></td><td>Custom playground tool chips</td><td><a href="./playground.html">Playground</a></td></tr><tr><td><code>agent/lib/</code></td><td>Import-only shared code, never discovered</td><td>None</td></tr><tr><td><code>evals/evals.config.ts</code></td><td>Shared eval settings (e.g. <code>maxConcurrency</code>); required when evals exist</td><td><a href="./../evals.html">Evals</a></td></tr><tr><td><code>evals/**/*.eval.ts</code></td><td>Filesystem evals; case id = path under <code>evals/</code></td><td><a href="./../evals.html">Evals</a></td></tr></tbody></table><p><code>agent/lib/</code> is the only place for shared code. Everything else under <code>agent/</code> is discovery surface. A stray <code>.ts</code> file in one of these folders is treated as a definition.</p><h2 id="why-didn-t-the-agent-sdk-discover-my-file" tabindex="-1">Why didn&#39;t the Agent SDK discover my file? <a class="header-anchor" href="#why-didn-t-the-agent-sdk-discover-my-file" aria-label="Permalink to &quot;Why didn&#39;t the Agent SDK discover my file?&quot;">​</a></h2><p>Run <code>agent-sdk validate --dir .</code> and <code>agent-sdk info --dir .</code>. <code>validate</code> prints diagnostics, and <code>serve</code> refuses to start on error-severity ones. Warnings, such as cloud runtime combined with local-only capabilities, print but don&#39;t block. <code>info</code> lists the discovered surface, so a missing tool or channel shows up immediately. From there, check the folder reference: the file is usually in the wrong directory or has the wrong extension.</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;"> validate</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;"> # diagnostics; non-zero exit on errors</span></span>
17
+ <span class="line"><span> └── readiness.eval.ts # regression cases</span></span></code></pre></div><p>Evals live in <code>evals/</code> at the project root, a sibling of <code>agent/</code>, never inside it. <code>agent/evals/</code> is silently ignored. See <a href="./../evals.html">Evals</a>.</p><h2 id="folder-reference" tabindex="-1">Folder reference <a class="header-anchor" href="#folder-reference" aria-label="Permalink to &quot;Folder reference&quot;">​</a></h2><p>Each path maps to a capability and a reference page.</p><table tabindex="0"><thead><tr><th>Path</th><th>What it is</th><th>Reference</th></tr></thead><tbody><tr><td><code>agent/agent.ts</code></td><td><code>defineAgent({ model?, runtime?, cloud?, local? })</code>; the model defaults to <code>grok-4.5</code> with <code>effort=high</code>, <code>fast=true</code></td><td><a href="./agent-config.html">Agent config</a></td></tr><tr><td><code>agent/instructions.md</code></td><td>Always-on system prompt, required on the root agent (<code>.ts</code> and directory forms exist)</td><td><a href="./instructions.html">Instructions</a></td></tr><tr><td><code>agent/tools/&lt;name&gt;.ts</code></td><td>One typed tool; filename = tool name. <code>execution: &quot;server&quot;</code> (in-process, default) or <code>&quot;agent&quot;</code> (a script that runs where the agent runs)</td><td><a href="./tools.html">Tools</a></td></tr><tr><td><code>agent/skills/*</code></td><td>SKILL.md-convention procedures, loaded on demand</td><td><a href="./skills.html">Skills</a></td></tr><tr><td><code>agent/mcp-connections/&lt;name&gt;.ts</code></td><td>MCP servers, available to the model, to server tools (<code>ctx.host.mcp</code>), and to channel/schedule handlers (<code>args.host.mcp</code>)</td><td><a href="./connections.html">MCP connections</a></td></tr><tr><td><code>agent/host-connections/&lt;name&gt;.ts</code></td><td>Privileged MCP servers for <code>ctx.host.mcp</code> and <code>mcp oauth</code>. The model never sees them.</td><td><a href="./connections.html">MCP connections</a></td></tr><tr><td><code>agent/subagents/&lt;id&gt;/</code></td><td>Child agent directory; <code>description</code> required</td><td><a href="./subagents.html">Subagents</a></td></tr><tr><td><code>agent/extensions/&lt;ns&gt;.ts</code> or <code>agent/extensions/&lt;ns&gt;/</code></td><td>A mounted extension or Cursor plugin; its contributions become <code>&lt;ns&gt;__&lt;name&gt;</code></td><td><a href="./extensions.html">Extensions</a></td></tr><tr><td><code>agent/channels/*.ts</code></td><td>HTTP surfaces beyond the built-in session API; <code>slack.ts</code> and <code>github.ts</code> use the platform packs</td><td><a href="./channels.html">Channels</a></td></tr><tr><td><code>agent/hooks/*.ts</code></td><td>Observe-only event subscribers, never fatal</td><td><a href="./hooks.html">Hooks</a></td></tr><tr><td><code>agent/otel.ts</code></td><td><code>defineOtel</code> OTLP export (traces, metrics, optional logs)</td><td><a href="./../guides/opentelemetry.html">OpenTelemetry</a></td></tr><tr><td><code>agent/storage.ts</code></td><td><code>defineStorage</code> backend for the durable <code>host.kv</code> / <code>host.files</code> APIs</td><td><a href="./../storage.html">Storage</a></td></tr><tr><td><code>agent/artifacts.ts</code></td><td><code>defineArtifacts</code> kinds, the <code>tag_artifact</code> opt-in, and retention</td><td><a href="./artifacts.html">Artifacts</a></td></tr><tr><td><code>agent/result.ts</code></td><td><code>defineResult</code> host <code>commit</code> on the final assistant text</td><td><a href="./result.html">Turn result</a></td></tr><tr><td><code>agent/schedules/*</code></td><td>Cron-driven runs (UTC, 5-field; never auto-fire under <code>--dev</code>)</td><td><a href="./schedules.html">Schedules</a></td></tr><tr><td><code>agent/sandbox/workspace/**</code></td><td>Seed files copied into each local session workspace</td><td><a href="./sessions.html#what-goes-into-a-local-session-workspace">Sessions</a></td></tr><tr><td><code>agent/playground/</code></td><td>Custom playground tool chips</td><td><a href="./playground.html">Playground</a></td></tr><tr><td><code>agent/lib/</code></td><td>Import-only shared code, never discovered</td><td>None</td></tr><tr><td><code>evals/evals.config.ts</code></td><td>Shared eval settings (e.g. <code>maxConcurrency</code>); required when evals exist</td><td><a href="./../evals.html">Evals</a></td></tr><tr><td><code>evals/**/*.eval.ts</code></td><td>Filesystem evals; case id = path under <code>evals/</code></td><td><a href="./../evals.html">Evals</a></td></tr></tbody></table><p><code>agent/lib/</code> is the only place for shared code. Everything else under <code>agent/</code> is discovery surface. A stray <code>.ts</code> file in one of these folders is treated as a definition.</p><h2 id="why-didn-t-the-agent-sdk-discover-my-file" tabindex="-1">Why didn&#39;t the Agent SDK discover my file? <a class="header-anchor" href="#why-didn-t-the-agent-sdk-discover-my-file" aria-label="Permalink to &quot;Why didn&#39;t the Agent SDK discover my file?&quot;">​</a></h2><p>Run <code>agent-sdk validate --dir .</code> and <code>agent-sdk info --dir .</code>. <code>validate</code> prints diagnostics, and <code>serve</code> refuses to start on error-severity ones. Warnings, such as cloud runtime combined with local-only capabilities, print but don&#39;t block. <code>info</code> lists the discovered surface, so a missing tool or channel shows up immediately. From there, check the folder reference: the file is usually in the wrong directory or has the wrong extension.</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;"> validate</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;"> # diagnostics; non-zero exit on errors</span></span>
18
18
  <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> info</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;"> # human-readable surface</span></span>
19
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> info</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;"> --json</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # machine-readable project info (same shape as GET /v1/info)</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="./agent-config.html">Agent config</a>: the runtime config at the root</li><li><a href="./tools.html">Tools</a>: add typed actions under <code>agent/tools/</code></li><li><a href="./../ab.html">Live A/B metrics</a>: compare variants from <code>agent/ab.ts</code> or <code>agent/ab/</code></li><li><a href="./../concepts.html">Concepts</a>: why the filesystem is the interface</li></ul>`,20)])])}const u=t(o,[["render",n]]);export{g as __pageData,u as default};
19
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> info</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;"> --json</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # machine-readable project info (same shape as GET /v1/info)</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="./agent-config.html">Agent config</a>: the runtime config at the root</li><li><a href="./tools.html">Tools</a>: add typed actions under <code>agent/tools/</code></li><li><a href="./../concepts.html">Concepts</a>: why the filesystem is the interface</li></ul>`,20)])])}const u=t(d,[["render",n]]);export{g as __pageData,u as default};
@@ -1 +1 @@
1
- import{_ as t,c as s,o as a,ag as d}from"./chunks/framework.BCISBCiQ.js";const g=JSON.parse('{"title":"Project layout","description":"The folder structure under agent/ and the path-derived naming rule.","frontmatter":{"title":"Project layout","description":"The folder structure under agent/ and the path-derived naming rule."},"headers":[],"relativePath":"reference/project-layout.md","filePath":"reference/project-layout.md"}'),o={name:"reference/project-layout.md"};function n(r,e,i,c,l,h){return a(),s("div",null,[...e[0]||(e[0]=[d("",20)])])}const u=t(o,[["render",n]]);export{g as __pageData,u as default};
1
+ import{_ as t,c as s,o as a,ag as o}from"./chunks/framework.BCISBCiQ.js";const g=JSON.parse('{"title":"Project layout","description":"The folder structure under agent/ and the path-derived naming rule.","frontmatter":{"title":"Project layout","description":"The folder structure under agent/ and the path-derived naming rule."},"headers":[],"relativePath":"reference/project-layout.md","filePath":"reference/project-layout.md"}'),d={name:"reference/project-layout.md"};function n(r,e,i,c,l,h){return a(),s("div",null,[...e[0]||(e[0]=[o("",20)])])}const u=t(d,[["render",n]]);export{g as __pageData,u as default};
@@ -0,0 +1 @@
1
+ import{_ as t,c as s,o as a,ag as o}from"./chunks/framework.BCISBCiQ.js";const u=JSON.parse('{"title":"Sessions, events, and streaming","description":"Understand how conversations continue, how events stream, and where session data lives.","frontmatter":{"title":"Sessions, events, and streaming","description":"Understand how conversations continue, how events stream, and where session data lives."},"headers":[],"relativePath":"reference/sessions.md","filePath":"reference/sessions.md"}'),n={name:"reference/sessions.md"};function d(i,e,r,c,l,h){return a(),s("div",null,[...e[0]||(e[0]=[o('<h1 id="sessions-events-and-streaming" tabindex="-1">Sessions, events, and streaming <a class="header-anchor" href="#sessions-events-and-streaming" aria-label="Permalink to &quot;Sessions, events, and streaming&quot;">​</a></h1><p>A session keeps one conversation, its workspace, and an append-only record of every message and tool call.</p><h2 id="what-does-a-session-contain" tabindex="-1">What does a session contain? <a class="header-anchor" href="#what-does-a-session-contain" aria-label="Permalink to &quot;What does a session contain?&quot;">​</a></h2><p>Each session combines:</p><ul><li>A channel and authenticated caller</li><li>A conversation the caller can continue</li><li>A workspace for local turns</li><li>An NDJSON event stream</li><li>Runtime state needed to resume after a server restart</li></ul><p>Sessions belong to the principal that created them. Follow-up, stream, and list routes return <code>403</code> when another caller tries to access one.</p><h2 id="which-session-identifier-should-i-use" tabindex="-1">Which session identifier should I use? <a class="header-anchor" href="#which-session-identifier-should-i-use" aria-label="Permalink to &quot;Which session identifier should I use?&quot;">​</a></h2><p>Sessions have two identifiers because conversation routing and inspection are different jobs.</p><table tabindex="0"><thead><tr><th>Identifier</th><th>Use it for</th></tr></thead><tbody><tr><td><code>continuationToken</code></td><td>Continue a conversation through its channel</td></tr><tr><td><code>sessionId</code></td><td>Stream events, inspect state, resolve approvals, or run a session-bound tool call</td></tr></tbody></table><p>Channels decide what a continuation token looks like. Slack uses its thread identity. A PR channel can use a key such as <code>pr:owner/repo#1</code>. The built-in HTTP API returns an opaque token and rotates it after each accepted follow-up. Reusing a stale HTTP token returns <code>409</code>.</p><p>Use the continuation token to keep talking. Use the session ID to observe or manage the stored session.</p><h2 id="which-session-modes-are-available" tabindex="-1">Which session modes are available? <a class="header-anchor" href="#which-session-modes-are-available" aria-label="Permalink to &quot;Which session modes are available?&quot;">​</a></h2><table tabindex="0"><thead><tr><th>Mode</th><th>Created by</th><th>What happens after a turn</th></tr></thead><tbody><tr><td><code>chat</code></td><td>HTTP sessions, channel <code>send</code>, Slack, or MCP <code>ask</code></td><td>Waits in <code>session.waiting</code> and accepts follow-ups</td></tr><tr><td><code>task</code></td><td>Markdown schedules and fire-and-forget dispatch</td><td>Ends in <code>session.completed</code> or <code>session.failed</code></td></tr></tbody></table><p>Task sessions don&#39;t accept follow-ups. Trying one returns <code>409</code>.</p><h2 id="what-happens-when-i-send-a-follow-up" tabindex="-1">What happens when I send a follow-up? <a class="header-anchor" href="#what-happens-when-i-send-a-follow-up" aria-label="Permalink to &quot;What happens when I send a follow-up?&quot;">​</a></h2><p>A follow-up to an idle chat session starts another turn. Admission when the session is already busy depends on the channel:</p><table tabindex="0"><thead><tr><th>Path</th><th>Busy-session policy</th></tr></thead><tbody><tr><td>HTTP playground / <code>POST /v1/session/:id</code> / MCP <code>ask</code></td><td><strong>Preempt</strong> (default): interrupt the in-flight turn, wait for it to settle, then run the new message</td></tr><tr><td>Slack mentions / DMs / alert-watch</td><td><strong>Coalesce</strong>: leave the active turn running, enqueue the follow-up, and drain queued asks into one follow-up turn when the active turn finishes (no mid-turn tool/hook inject)</td></tr></tbody></table><p>Pass <code>admission: &quot;coalesce&quot;</code> on <code>send()</code> to opt into the Slack policy from other callers. Omit it (or pass <code>&quot;preempt&quot;</code>) to keep interrupt semantics.</p><p><code>POST /v1/session/:id/stop</code> interrupts a turn without sending a new message. Interrupted turns record <code>turn.failed</code> with <code>&quot;turn interrupted&quot;</code>. This means the turn was preempted. A whole-message Slack <code>stop</code> / <code>@agent stop</code> does the same for that thread and clears pending coalesced nudges.</p><p>Session-bound deterministic tool calls share the lock only for writes: a write-effect call returns <code>409 session_busy</code> while a model turn is running, a read-effect call runs alongside the turn (see <a href="./tools.html#call-a-tool-without-a-model-turn">Tools</a>).</p><h2 id="which-events-can-i-stream" tabindex="-1">Which events can I stream? <a class="header-anchor" href="#which-events-can-i-stream" aria-label="Permalink to &quot;Which events can I stream?&quot;">​</a></h2><p>Each NDJSON line uses this envelope: <code>{ type, index, sessionId, turnId?, at, data }</code>. The <code>index</code> increases within one session. The <code>at</code> field is an ISO-8601 timestamp.</p><table tabindex="0"><thead><tr><th>Phase</th><th>Events</th><th>What they tell you</th></tr></thead><tbody><tr><td>Session</td><td><code>session.started</code>, <code>session.waiting</code>, <code>session.completed</code>, <code>session.failed</code></td><td>Session creation, readiness, and task completion</td></tr><tr><td>Agent</td><td><code>agent.bound</code></td><td>Cloud conversation URL</td></tr><tr><td>Input</td><td><code>message.received</code></td><td>A user message was accepted</td></tr><tr><td>Turn</td><td><code>turn.queued</code>, <code>turn.started</code>, <code>turn.completed</code>, <code>turn.failed</code></td><td>Queue position under a <a href="./agent-config.html#concurrency"><code>maxRunningTurns</code> cap</a>, then turn status, final result, and token usage</td></tr><tr><td>Steps</td><td><code>step.started</code>, <code>step.completed</code></td><td>Model step boundaries and duration</td></tr><tr><td>Reasoning</td><td><code>reasoning.appended</code>, <code>reasoning.completed</code></td><td>Streamed reasoning blocks</td></tr><tr><td>Reply</td><td><code>message.appended</code>, <code>message.completed</code></td><td>Text deltas and finalized assistant messages</td></tr><tr><td>Tools</td><td><code>actions.requested</code>, <code>action.result</code></td><td>Tool names, validated arguments, outputs, and errors</td></tr><tr><td>Approvals</td><td><code>action.approval_requested</code>, <code>action.approval_resolved</code></td><td>A parked tool call and the human decision</td></tr><tr><td>Subagents</td><td><code>subagent.called</code>, <code>subagent.completed</code></td><td>Delegated work</td></tr><tr><td>Artifacts</td><td><code>artifact.tagged</code></td><td>A durable <a href="./artifacts.html">artifact</a> was tagged for this session, by host code or <code>tag_artifact</code></td></tr></tbody></table><p>Pair <code>actions.requested</code> with <code>action.result</code> to reconstruct the tool trajectory. Read <code>turn.completed.data.usage</code> for input, output, and cache token counts. When <code>agent/result.ts</code> is authored, a thrown <code>commit</code> or empty assistant text emits <code>turn.failed</code> instead of <code>turn.completed</code>. See <a href="./result.html">Turn result</a>.</p><h2 id="how-do-i-stream-or-replay-session-events" tabindex="-1">How do I stream or replay session events? <a class="header-anchor" href="#how-do-i-stream-or-replay-session-events" aria-label="Permalink to &quot;How do I stream or replay session events?&quot;">​</a></h2><p>One endpoint handles both live streaming and replay:</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;">curl</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -N</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;http://127.0.0.1:3000/&lt;slug&gt;/v1/session/ses_…/stream?startIndex=0&#39;</span></span></code></pre></div><p>Pass <code>startIndex</code> to continue after the last event you received. Omit it or pass <code>0</code> to replay the full session before following new events. <code>GET /v1/session/:id/events</code> returns a one-time dump without staying connected.</p><p>Event streams replay from disk after a server restart. Conversation state resumes from the Cursor SDK store.</p><h2 id="what-goes-into-a-local-session-workspace" tabindex="-1">What goes into a local session workspace? <a class="header-anchor" href="#what-goes-into-a-local-session-workspace" aria-label="Permalink to &quot;What goes into a local session workspace?&quot;">​</a></h2><p>The Agent SDK creates a workspace before the first local turn:</p><table tabindex="0"><thead><tr><th>Source path</th><th>Lands as</th></tr></thead><tbody><tr><td><code>instructions.*</code></td><td><code>AGENTS.md</code></td></tr><tr><td><code>skills/*</code></td><td><code>.cursor/skills/&lt;name&gt;/SKILL.md</code></td></tr><tr><td>agent tools (<code>execution: &quot;agent&quot;</code>)</td><td>scripts in the session workspace, with a catalog in <code>AGENTS.md</code></td></tr><tr><td><code>sandbox/workspace/**</code></td><td>copied in as seed files</td></tr><tr><td>per-send <code>workspaceFiles</code></td><td>written before the turn</td></tr></tbody></table><p>The local harness uses this workspace as its working directory. Parent directories can contribute <code>AGENTS.md</code> and <code>.cursor</code> settings. Set <code>local.cwd</code> when you need a clean parent directory. A channel can also provide a different working directory for one session, such as a PR worktree.</p><p>See <a href="./agent-config.html#local-cwd">Agent config: local cwd</a> for the inheritance rules.</p><h2 id="where-does-the-agent-sdk-store-session-data" tabindex="-1">Where does the Agent SDK store session data? <a class="header-anchor" href="#where-does-the-agent-sdk-store-session-data" aria-label="Permalink to &quot;Where does the Agent SDK store session data?&quot;">​</a></h2><p>Local state lives under <code>--state-root</code>. Slugged mounts store it under a subdirectory named for the slug.</p><p>Deleting a session directory removes the session from the server: it disappears from listings and can no longer be streamed or continued. Cloud conversations remain on the Cursor backend.</p><p>Nested git checkouts already default <code>local.cwd</code> outside the enclosing repo. See <a href="./../concepts.html#what-files-can-a-local-session-access">local session workspaces</a>.</p><h2 id="how-do-i-inspect-a-saved-event-stream" tabindex="-1">How do I inspect a saved event stream? <a class="header-anchor" href="#how-do-i-inspect-a-saved-event-stream" aria-label="Permalink to &quot;How do I inspect a saved event stream?&quot;">​</a></h2><p>Use <code>trajectory</code> with a saved trace:</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;"> trajectory</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --events</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> &lt;</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">state-roo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">t</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&gt;</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">/traces/</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&lt;</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">sessionI</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">d</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&gt;</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.ndjson</span></span></code></pre></div><p>The command prints tool calls, the reply, and token usage in the same JSON shape as <code>run</code>. Use <strong>Open trace</strong> in the playground for a visual view.</p><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="./http-api.html">HTTP API</a></li><li><a href="./hooks.html">Hooks</a></li><li><a href="./../concepts.html">How the Agent SDK works</a></li></ul>',44)])])}const m=t(n,[["render",d]]);export{u as __pageData,m as default};
@@ -1 +1 @@
1
- import{_ as o,c as a,o as t,ag as l}from"./chunks/framework.BCISBCiQ.js";const f=JSON.parse('{"title":"Scaffold an agent with Cursor","description":"Use the bundled create-agent skill to plan, build, and verify a new agent.","frontmatter":{"title":"Scaffold an agent with Cursor","description":"Use the bundled create-agent skill to plan, build, and verify a new agent."},"headers":[],"relativePath":"scaffolding-agents.md","filePath":"scaffolding-agents.md"}'),s={name:"scaffolding-agents.md"};function i(r,e,n,d,c,h){return t(),a("div",null,[...e[0]||(e[0]=[l('<h1 id="scaffold-an-agent-with-cursor" tabindex="-1">Scaffold an agent with Cursor <a class="header-anchor" href="#scaffold-an-agent-with-cursor" aria-label="Permalink to &quot;Scaffold an agent with Cursor&quot;">​</a></h1><p>Turn an idea into a verified agent while Cursor guides you through each decision.</p><h2 id="what-does-the-create-agent-skill-do" tabindex="-1">What does the create-agent skill do? <a class="header-anchor" href="#what-does-the-create-agent-skill-do" aria-label="Permalink to &quot;What does the create-agent skill do?&quot;">​</a></h2><p>The bundled <a href="./skills/create-agent.html"><code>create-agent</code> skill</a> turns your goal into a small working project. Have Cursor read that file and follow it.</p><p>Where to find the file depends on how you got the package:</p><ul><li>Installing <code>@cursor/july</code> (<code>npm install</code>, <code>npx @cursor/july</code>, a version bump) copies every package skill into <code>~/.cursor/skills/agentsdk/</code> with <code>alwaysApply: true</code>, so Cursor injects the skill body into context instead of waiting for the model to pick it from the catalog. The <code>/</code> menu lists them as <code>/agentsdk-create-agent</code>, <code>/agentsdk-hillclimb</code>, and the rest. Re-installing overwrites those copies with the package version.</li><li>Installed <code>@cursor/july</code> as a dependency? The skill also ships inside the package at <code>node_modules/@cursor/july/skills/create-agent/SKILL.md</code>.</li><li>Working from this package&#39;s source? The skill is at <a href="./skills/create-agent.html"><code>skills/create-agent/SKILL.md</code></a>. Run <code>agent-sdk install-skills</code> if you want the same copies in <code>~/.cursor/skills/agentsdk/</code> (the package postinstall skips the source checkout).</li></ul><p>Cursor will:</p><ul><li>Ask only for choices missing from your prompt</li><li>Recommend defaults based on what you want to build</li><li>Show you the plan and file tree before writing files</li><li>Create the agent after you confirm the plan</li><li>Run structural checks, a real turn, and a smoke eval</li></ul><p>Use this skill for a new agent. Use <a href="./guides/convert-automation.html">convert-automation</a> when the starting point is a Cursor Automation in the dashboard. Use <a href="./hillclimbing.html"><code>hillclimb</code></a> (<code>skills/hillclimb/SKILL.md</code>) when an existing agent works but needs better results.</p><h2 id="how-do-i-start-a-guided-scaffold" tabindex="-1">How do I start a guided scaffold? <a class="header-anchor" href="#how-do-i-start-a-guided-scaffold" aria-label="Permalink to &quot;How do I start a guided scaffold?&quot;">​</a></h2><p>Describe the outcome and any constraints you already know:</p><blockquote><p>Build a local weather agent for the playground. Give it one tool for current conditions and add a smoke eval. Guide me through the remaining decisions.</p></blockquote><p>More detail means fewer questions. Include a channel, runtime, model, or required integration when those choices are fixed.</p><h2 id="which-choices-will-cursor-ask-me-to-make" tabindex="-1">Which choices will Cursor ask me to make? <a class="header-anchor" href="#which-choices-will-cursor-ask-me-to-make" aria-label="Permalink to &quot;Which choices will Cursor ask me to make?&quot;">​</a></h2><p>Cursor fills gaps in two short rounds:</p><ul><li><strong>Identity:</strong> purpose, project name, and location</li><li><strong>Runtime:</strong> local or cloud</li><li><strong>Model:</strong> the default model or another Cursor model</li><li><strong>Channels:</strong> playground and HTTP, Slack, GitHub, a webhook, or a schedule</li><li><strong>MCP connections:</strong> remote or local MCP servers</li><li><strong>Capabilities:</strong> tools, skills, subagents, hooks, seed files, approvals, and evals</li></ul><p>Questions adapt to your goal. A playground chat agent won&#39;t get cloud-repository questions. A local agent won&#39;t get cloud setup questions.</p><h2 id="what-happens-before-cursor-writes-files" tabindex="-1">What happens before Cursor writes files? <a class="header-anchor" href="#what-happens-before-cursor-writes-files" aria-label="Permalink to &quot;What happens before Cursor writes files?&quot;">​</a></h2><p>Cursor shows one plan with the choices it made and the folders it will create. Choose <strong>Scaffold it</strong> to continue or <strong>Adjust something</strong> to change the plan.</p><p>No files change before you approve this step.</p><h2 id="what-will-cursor-create" tabindex="-1">What will Cursor create? <a class="header-anchor" href="#what-will-cursor-create" aria-label="Permalink to &quot;What will Cursor create?&quot;">​</a></h2><p>A first version usually includes:</p><ul><li><code>AGENTS.md</code>, <code>.gitignore</code>, <code>package.json</code>, and <code>tsconfig.json</code></li><li><code>agent/agent.ts</code> for the model and runtime</li><li><code>agent/instructions.md</code> for the always-on prompt</li><li><code>agent/hooks/memory.ts</code> for memory guidance</li><li>One or two tools under <code>agent/tools/</code></li><li>Any channels or MCP connections you selected</li><li><code>evals/evals.config.ts</code> and one smoke eval</li></ul><p>Cursor keeps the first version small. Side-effecting server tools use <code>needsApproval</code>. Deterministic setup, such as fetching a pull request, stays in host code instead of model instructions.</p><p>See <a href="./reference/project-layout.html">Project layout</a> for every supported folder.</p><h2 id="how-does-cursor-verify-the-scaffold" tabindex="-1">How does Cursor verify the scaffold? <a class="header-anchor" href="#how-does-cursor-verify-the-scaffold" aria-label="Permalink to &quot;How does Cursor verify the scaffold?&quot;">​</a></h2><p>Cursor checks the project in this order:</p><ol><li>Run <code>agent-sdk validate</code> and fix every error</li><li>Inspect the discovered surface with <code>info --json</code></li><li>Call each server tool directly with validated sample input</li><li>Run one end-to-end model turn</li><li>Run the smoke eval</li><li>Run the project&#39;s TypeScript check</li></ol><p>Validation, discovery, direct server-tool calls, and server startup work without a Cursor credential. Model turns and evals need <code>CURSOR_API_KEY</code> or a saved <code>agent-sdk login</code>.</p><h2 id="what-happens-after-the-first-agent-works" tabindex="-1">What happens after the first agent works? <a class="header-anchor" href="#what-happens-after-the-first-agent-works" aria-label="Permalink to &quot;What happens after the first agent works?&quot;">​</a></h2><p>Choose one to three fixed inputs, define what should improve, and name what must stay unchanged. Then have Cursor follow <a href="./skills/hillclimb.html"><code>skills/hillclimb/SKILL.md</code></a>.</p><p>The hillclimb skill measures a baseline, changes one lever, runs the same inputs again, and adds an eval for each improvement you keep.</p><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="./quickstart.html">Build your first PR reviewer</a></li><li><a href="./guides/convert-automation.html">Convert a Cursor Automation</a></li><li><a href="./building-with-agents.html">Building agents with agents</a></li><li><a href="./evals.html">Evals</a></li><li><a href="./hillclimbing.html">Hillclimbing</a></li><li><a href="./reference/project-layout.html">Project layout</a></li></ul>',34)])])}const p=o(s,[["render",i]]);export{f as __pageData,p as default};
1
+ import{_ as o,c as a,o as t,ag as l}from"./chunks/framework.BCISBCiQ.js";const f=JSON.parse('{"title":"Scaffold an agent with Cursor","description":"Use the bundled create-agent skill to plan, build, and verify a new agent.","frontmatter":{"title":"Scaffold an agent with Cursor","description":"Use the bundled create-agent skill to plan, build, and verify a new agent."},"headers":[],"relativePath":"scaffolding-agents.md","filePath":"scaffolding-agents.md"}'),s={name:"scaffolding-agents.md"};function i(r,e,n,d,c,h){return t(),a("div",null,[...e[0]||(e[0]=[l('<h1 id="scaffold-an-agent-with-cursor" tabindex="-1">Scaffold an agent with Cursor <a class="header-anchor" href="#scaffold-an-agent-with-cursor" aria-label="Permalink to &quot;Scaffold an agent with Cursor&quot;">​</a></h1><p>Turn an idea into a verified agent while Cursor guides you through each decision.</p><h2 id="what-does-the-create-agent-skill-do" tabindex="-1">What does the create-agent skill do? <a class="header-anchor" href="#what-does-the-create-agent-skill-do" aria-label="Permalink to &quot;What does the create-agent skill do?&quot;">​</a></h2><p>The bundled <a href="./skills/create-agent.html"><code>create-agent</code> skill</a> turns your goal into a small working project. Have Cursor read that file and follow it.</p><p>Where to find the file depends on how you got the package:</p><ul><li>Installing <code>@cursor/july</code> (<code>npm install</code>, <code>npx @cursor/july</code>, a version bump) copies every package skill into <code>~/.cursor/skills/agentsdk/</code> with <code>alwaysApply: true</code>, so Cursor injects the skill body into context instead of waiting for the model to pick it from the catalog. The <code>/</code> menu lists them as <code>/agentsdk-create-agent</code>, <code>/agentsdk-hillclimb</code>, and the rest. Re-installing overwrites those copies with the package version.</li><li>Installed <code>@cursor/july</code> as a dependency? The skill also ships inside the package at <code>node_modules/@cursor/july/skills/create-agent/SKILL.md</code>.</li><li>Working from this package&#39;s source? The skill is at <a href="./skills/create-agent.html"><code>skills/create-agent/SKILL.md</code></a>. Run <code>agent-sdk install-skills</code> if you want the same copies in <code>~/.cursor/skills/agentsdk/</code> (the package postinstall skips the source checkout).</li></ul><p>Cursor will:</p><ul><li>Ask only for choices missing from your prompt</li><li>Recommend defaults based on what you want to build</li><li>Show you the plan and file tree before writing files</li><li>Create the agent after you confirm the plan</li><li>Run structural checks, a real turn, and a smoke eval</li></ul><p>Use this skill for a new agent. Use <a href="./guides/convert-automation.html">convert-automation</a> when the starting point is a Cursor Automation in the dashboard. Use <a href="./hillclimbing.html"><code>hillclimb</code></a> (<code>skills/hillclimb/SKILL.md</code>) when an existing agent works but needs better results.</p><h2 id="how-do-i-start-a-guided-scaffold" tabindex="-1">How do I start a guided scaffold? <a class="header-anchor" href="#how-do-i-start-a-guided-scaffold" aria-label="Permalink to &quot;How do I start a guided scaffold?&quot;">​</a></h2><p>Describe the outcome and any constraints you already know:</p><blockquote><p>Build a local weather agent for the playground. Give it one tool for current conditions and add a smoke eval. Guide me through the remaining decisions.</p></blockquote><p>More detail means fewer questions. Include a channel, runtime, model, or required integration when those choices are fixed.</p><h2 id="which-choices-will-cursor-ask-me-to-make" tabindex="-1">Which choices will Cursor ask me to make? <a class="header-anchor" href="#which-choices-will-cursor-ask-me-to-make" aria-label="Permalink to &quot;Which choices will Cursor ask me to make?&quot;">​</a></h2><p>Cursor fills gaps in two short rounds:</p><ul><li><strong>Identity:</strong> purpose, project name, and location</li><li><strong>Runtime:</strong> local or cloud</li><li><strong>Model:</strong> the default model or another Cursor model</li><li><strong>Channels:</strong> playground and HTTP, Slack, GitHub, a webhook, or a schedule</li><li><strong>MCP connections:</strong> remote or local MCP servers</li><li><strong>Capabilities:</strong> tools, skills, subagents, hooks, seed files, approvals, and evals</li></ul><p>Questions adapt to your goal. A playground chat agent won&#39;t get cloud-repository questions. A local agent won&#39;t get cloud setup questions.</p><h2 id="what-happens-before-cursor-writes-files" tabindex="-1">What happens before Cursor writes files? <a class="header-anchor" href="#what-happens-before-cursor-writes-files" aria-label="Permalink to &quot;What happens before Cursor writes files?&quot;">​</a></h2><p>Cursor shows one plan with the choices it made and the folders it will create. Choose <strong>Scaffold it</strong> to continue or <strong>Adjust something</strong> to change the plan.</p><p>No files change before you approve this step.</p><h2 id="what-will-cursor-create" tabindex="-1">What will Cursor create? <a class="header-anchor" href="#what-will-cursor-create" aria-label="Permalink to &quot;What will Cursor create?&quot;">​</a></h2><p>A first version usually includes:</p><ul><li><code>AGENTS.md</code>, <code>.gitignore</code>, <code>package.json</code>, and <code>tsconfig.json</code></li><li><code>agent/agent.ts</code> for the model and runtime</li><li><code>agent/instructions.md</code> for the always-on prompt</li><li><code>agent/hooks/memory.ts</code> for memory guidance</li><li>One or two tools under <code>agent/tools/</code></li><li>Any channels or MCP connections you selected</li><li><code>evals/evals.config.ts</code> and one smoke eval</li></ul><p>Cursor keeps the first version small. Side-effecting server tools use <code>needsApproval</code>. Deterministic setup, such as fetching a pull request, stays in host code instead of model instructions.</p><p>See <a href="./reference/project-layout.html">Project layout</a> for every supported folder.</p><h2 id="how-does-cursor-verify-the-scaffold" tabindex="-1">How does Cursor verify the scaffold? <a class="header-anchor" href="#how-does-cursor-verify-the-scaffold" aria-label="Permalink to &quot;How does Cursor verify the scaffold?&quot;">​</a></h2><p>Cursor checks the project in this order:</p><ol><li>Run <code>agent-sdk validate</code> and fix every error</li><li>Inspect the discovered surface with <code>info --json</code></li><li>Call each server tool directly with validated sample input</li><li>Run one end-to-end model turn</li><li>Run the smoke eval</li><li>Run the project&#39;s TypeScript check</li></ol><p>Validation, discovery, direct server-tool calls, and server startup work without a Cursor credential. Model turns and evals need <code>CURSOR_API_KEY</code>, then <code>CURSOR_API_KEY_FILE</code> (hosted default <code>/run/cursor/secrets/CURSOR_API_KEY</code>), then <code>CURSOR_SERVICE_ACCOUNT_KEY</code>, then a saved <code>agent-sdk login</code>.</p><h2 id="what-happens-after-the-first-agent-works" tabindex="-1">What happens after the first agent works? <a class="header-anchor" href="#what-happens-after-the-first-agent-works" aria-label="Permalink to &quot;What happens after the first agent works?&quot;">​</a></h2><p>Choose one to three fixed inputs, define what should improve, and name what must stay unchanged. Then have Cursor follow <a href="./skills/hillclimb.html"><code>skills/hillclimb/SKILL.md</code></a>.</p><p>The hillclimb skill measures a baseline, changes one lever, runs the same inputs again, and adds an eval for each improvement you keep.</p><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="./quickstart.html">Build your first PR reviewer</a></li><li><a href="./guides/convert-automation.html">Convert a Cursor Automation</a></li><li><a href="./building-with-agents.html">Building agents with agents</a></li><li><a href="./evals.html">Evals</a></li><li><a href="./hillclimbing.html">Hillclimbing</a></li><li><a href="./reference/project-layout.html">Project layout</a></li></ul>',34)])])}const p=o(s,[["render",i]]);export{f as __pageData,p as default};