@cursor/july 0.1.104 → 0.1.107

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 (286) hide show
  1. package/dist/bin/agent-serve.js +1 -8
  2. package/dist/channels/bitbucket/types.d.ts +2 -4
  3. package/dist/channels/bitbucket/types.d.ts.map +1 -1
  4. package/dist/channels/deployments/deployments-channel.d.ts.map +1 -1
  5. package/dist/channels/deployments/deployments-channel.js +1 -0
  6. package/dist/channels/deployments/types.d.ts +7 -8
  7. package/dist/channels/deployments/types.d.ts.map +1 -1
  8. package/dist/channels/github/types.d.ts +2 -4
  9. package/dist/channels/github/types.d.ts.map +1 -1
  10. package/dist/channels/gitlab/types.d.ts +2 -5
  11. package/dist/channels/gitlab/types.d.ts.map +1 -1
  12. package/dist/channels/origin/types.d.ts +2 -3
  13. package/dist/channels/origin/types.d.ts.map +1 -1
  14. package/dist/channels/slack/defaults.d.ts.map +1 -1
  15. package/dist/channels/slack/defaults.js +3 -0
  16. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  17. package/dist/channels/slack/dispatch.js +1 -1
  18. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  19. package/dist/channels/slack/live-delivery.js +48 -11
  20. package/dist/channels/slack/types.d.ts +4 -3
  21. package/dist/channels/slack/types.d.ts.map +1 -1
  22. package/dist/docs/404.html +3 -3
  23. package/dist/docs/ab.html +6 -6
  24. package/dist/docs/assets/{app.DbMWUyGb.js → app.CtuckIiL.js} +1 -1
  25. package/dist/docs/assets/chunks/@localSearchIndexroot.DXXZxiMv.js +1 -0
  26. package/dist/docs/assets/chunks/{VPLocalSearchBox.DcNeTh9o.js → VPLocalSearchBox.Bkkhnu8K.js} +2 -2
  27. package/dist/docs/assets/chunks/{theme.DMjhY3gl.js → theme.DhpIe0Pa.js} +2 -2
  28. package/dist/docs/assets/guides_grokbot-agents.md.DVqdhBKb.js +9 -0
  29. package/dist/docs/assets/guides_grokbot-agents.md.DVqdhBKb.lean.js +1 -0
  30. package/dist/docs/assets/{guides_opentelemetry.md.COh9jFVg.js → guides_opentelemetry.md.SCRMskno.js} +3 -3
  31. package/dist/docs/assets/{guides_opentelemetry.md.COh9jFVg.lean.js → guides_opentelemetry.md.SCRMskno.lean.js} +1 -1
  32. package/dist/docs/assets/index.md.BW_6tOgR.js +5 -0
  33. package/dist/docs/assets/index.md.BW_6tOgR.lean.js +1 -0
  34. package/dist/docs/assets/{reference_channels.md.DBGcaB7m.js → reference_channels.md.D-qTqwcq.js} +2 -2
  35. package/dist/docs/assets/{reference_channels.md.DBGcaB7m.lean.js → reference_channels.md.D-qTqwcq.lean.js} +1 -1
  36. package/dist/docs/assets/{reference_cli.md.CJNc_xYK.js → reference_cli.md.Dm67hd2D.js} +3 -2
  37. package/dist/docs/assets/{reference_extensions.md.DykHW3qL.js → reference_extensions.md.CGmMLblt.js} +1 -1
  38. package/dist/docs/assets/{skills_otel.md.CqhobH3B.js → skills_otel.md.B5Ddv1xH.js} +1 -1
  39. package/dist/docs/assets/{style.BRuM8477.css → style.DCD_zyg3.css} +1 -1
  40. package/dist/docs/assets/templates_grokbot-agents.md.c1s6Flp9.js +3 -0
  41. package/dist/docs/assets/templates_grokbot-agents.md.c1s6Flp9.lean.js +1 -0
  42. package/dist/docs/building-with-agents.html +6 -6
  43. package/dist/docs/concepts.html +5 -5
  44. package/dist/docs/deployment.html +6 -6
  45. package/dist/docs/evals.html +6 -6
  46. package/dist/docs/guides/agent-to-agent.html +6 -6
  47. package/dist/docs/guides/cloud-agents.html +6 -6
  48. package/dist/docs/guides/convert-automation.html +6 -6
  49. package/dist/docs/guides/github.html +6 -6
  50. package/dist/docs/guides/grokbot-agents.html +35 -0
  51. package/dist/docs/guides/grokbot-agents.md +88 -0
  52. package/dist/docs/guides/human-in-the-loop.html +6 -6
  53. package/dist/docs/guides/mcp-oauth.html +6 -6
  54. package/dist/docs/guides/opentelemetry.html +8 -8
  55. package/dist/docs/guides/opentelemetry.md +3 -4
  56. package/dist/docs/guides/slack.html +6 -6
  57. package/dist/docs/guides/webhooks.html +6 -6
  58. package/dist/docs/hashmap.json +1 -1
  59. package/dist/docs/hillclimbing.html +6 -6
  60. package/dist/docs/index.html +8 -8
  61. package/dist/docs/index.md +6 -1
  62. package/dist/docs/llms-full.txt +178 -30
  63. package/dist/docs/llms.txt +2 -0
  64. package/dist/docs/quickstart.html +6 -6
  65. package/dist/docs/reference/agent-config.html +6 -6
  66. package/dist/docs/reference/artifacts.html +6 -6
  67. package/dist/docs/reference/channels.html +7 -7
  68. package/dist/docs/reference/channels.md +11 -19
  69. package/dist/docs/reference/cli.html +10 -9
  70. package/dist/docs/reference/cli.md +7 -3
  71. package/dist/docs/reference/connections.html +6 -6
  72. package/dist/docs/reference/extensions.html +7 -7
  73. package/dist/docs/reference/extensions.md +2 -0
  74. package/dist/docs/reference/hooks.html +6 -6
  75. package/dist/docs/reference/http-api.html +6 -6
  76. package/dist/docs/reference/instructions.html +6 -6
  77. package/dist/docs/reference/playground.html +5 -5
  78. package/dist/docs/reference/project-layout.html +6 -6
  79. package/dist/docs/reference/prompt.html +6 -6
  80. package/dist/docs/reference/result.html +6 -6
  81. package/dist/docs/reference/schedules.html +6 -6
  82. package/dist/docs/reference/sessions.html +5 -5
  83. package/dist/docs/reference/skills.html +6 -6
  84. package/dist/docs/reference/subagents.html +6 -6
  85. package/dist/docs/reference/tools.html +6 -6
  86. package/dist/docs/scaffolding-agents.html +5 -5
  87. package/dist/docs/skills/ab.html +6 -6
  88. package/dist/docs/skills/create-agent.html +6 -6
  89. package/dist/docs/skills/debug.html +5 -5
  90. package/dist/docs/skills/evals.html +6 -6
  91. package/dist/docs/skills/framework-map.html +5 -5
  92. package/dist/docs/skills/github.html +6 -6
  93. package/dist/docs/skills/hillclimb.html +6 -6
  94. package/dist/docs/skills/index.html +5 -5
  95. package/dist/docs/skills/mcp-auth.html +6 -6
  96. package/dist/docs/skills/otel.html +8 -8
  97. package/dist/docs/skills/otel.md +3 -3
  98. package/dist/docs/skills/setup-slack.html +6 -6
  99. package/dist/docs/storage.html +6 -6
  100. package/dist/docs/templates/agentic-owners.html +6 -6
  101. package/dist/docs/templates/agents-md.html +6 -6
  102. package/dist/docs/templates/code-wiki.html +6 -6
  103. package/dist/docs/templates/demo.html +6 -6
  104. package/dist/docs/templates/grokbot-agents.html +29 -0
  105. package/dist/docs/templates/grokbot-agents.md +48 -0
  106. package/dist/docs/templates/pr-autofixer.html +6 -6
  107. package/dist/docs/templates/security-help.html +6 -6
  108. package/dist/docs/templates/security-reviewer.html +6 -6
  109. package/dist/docs/templates/triage.html +6 -6
  110. package/dist/docs/troubleshooting.html +5 -5
  111. package/dist/files.d.ts +7 -2
  112. package/dist/files.d.ts.map +1 -1
  113. package/dist/files.js +7 -2
  114. package/dist/index.d.ts +4 -5
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +3 -4
  117. package/dist/internal/cli-deploy.d.ts.map +1 -1
  118. package/dist/internal/cli-deploy.js +23 -11
  119. package/dist/internal/cursor/backend-client.d.ts +25 -0
  120. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  121. package/dist/internal/cursor/backend-client.js +57 -2
  122. package/dist/internal/cursor-agent-template.d.ts +1 -1
  123. package/dist/internal/cursor-agent-template.d.ts.map +1 -1
  124. package/dist/internal/cursor-agent-template.js +1 -0
  125. package/dist/internal/deploy-client.d.ts +8 -0
  126. package/dist/internal/deploy-client.d.ts.map +1 -1
  127. package/dist/internal/deploy-client.js +14 -0
  128. package/dist/internal/deploy-manifest.d.ts +3 -0
  129. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  130. package/dist/internal/deploy-manifest.js +15 -12
  131. package/dist/internal/discovery/agent.d.ts.map +1 -1
  132. package/dist/internal/discovery/agent.js +1 -0
  133. package/dist/internal/discovery/info.d.ts.map +1 -1
  134. package/dist/internal/discovery/info.js +7 -3
  135. package/dist/internal/discovery/modules.d.ts +1 -1
  136. package/dist/internal/discovery/modules.d.ts.map +1 -1
  137. package/dist/internal/discovery/modules.js +1 -0
  138. package/dist/internal/discovery/project.d.ts.map +1 -1
  139. package/dist/internal/discovery/project.js +3 -0
  140. package/dist/internal/discovery/reminders.d.ts +7 -0
  141. package/dist/internal/discovery/reminders.d.ts.map +1 -0
  142. package/dist/internal/discovery/reminders.js +65 -0
  143. package/dist/internal/discovery/subagent.js +1 -0
  144. package/dist/internal/distribution.d.ts +5 -0
  145. package/dist/internal/distribution.d.ts.map +1 -1
  146. package/dist/internal/distribution.js +17 -0
  147. package/dist/internal/framework-file-storage.d.ts +3 -1
  148. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  149. package/dist/internal/framework-file-storage.js +3 -1
  150. package/dist/internal/framework-storage-selection.d.ts +14 -3
  151. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  152. package/dist/internal/framework-storage-selection.js +36 -6
  153. package/dist/internal/guest-network.d.ts.map +1 -1
  154. package/dist/internal/guest-network.js +2 -0
  155. package/dist/internal/hosted-delivery-protocol.d.ts +48 -0
  156. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  157. package/dist/internal/hosted-delivery-protocol.js +60 -0
  158. package/dist/internal/hosted-delivery.d.ts +17 -0
  159. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  160. package/dist/internal/hosted-delivery.js +112 -19
  161. package/dist/internal/hosted-managed-automation.d.ts.map +1 -1
  162. package/dist/internal/hosted-managed-automation.js +27 -2
  163. package/dist/internal/init-project.d.ts.map +1 -1
  164. package/dist/internal/init-project.js +4 -1
  165. package/dist/internal/local-control-plane.d.ts +18 -2
  166. package/dist/internal/local-control-plane.d.ts.map +1 -1
  167. package/dist/internal/local-control-plane.js +199 -17
  168. package/dist/internal/reminder-control-plane-protocol.d.ts +187 -0
  169. package/dist/internal/reminder-control-plane-protocol.d.ts.map +1 -0
  170. package/dist/internal/reminder-control-plane-protocol.js +244 -0
  171. package/dist/internal/reminder-runner.d.ts +48 -6
  172. package/dist/internal/reminder-runner.d.ts.map +1 -1
  173. package/dist/internal/reminder-runner.js +336 -48
  174. package/dist/internal/reminder-schedule.d.ts +5 -2
  175. package/dist/internal/reminder-schedule.d.ts.map +1 -1
  176. package/dist/internal/reminder-schedule.js +8 -6
  177. package/dist/internal/reminder-store.d.ts +24 -7
  178. package/dist/internal/reminder-store.d.ts.map +1 -1
  179. package/dist/internal/reminder-store.js +6 -5
  180. package/dist/internal/request-error-status.d.ts +2 -0
  181. package/dist/internal/request-error-status.d.ts.map +1 -1
  182. package/dist/internal/request-error-status.js +22 -3
  183. package/dist/internal/scm/pr-url.d.ts +40 -0
  184. package/dist/internal/scm/pr-url.d.ts.map +1 -1
  185. package/dist/internal/scm/pr-url.js +93 -14
  186. package/dist/internal/sdk-runner.d.ts +12 -0
  187. package/dist/internal/sdk-runner.d.ts.map +1 -1
  188. package/dist/internal/sdk-runner.js +18 -0
  189. package/dist/internal/server.d.ts.map +1 -1
  190. package/dist/internal/server.js +78 -30
  191. package/dist/internal/session-engine.d.ts +12 -0
  192. package/dist/internal/session-engine.d.ts.map +1 -1
  193. package/dist/internal/session-engine.js +137 -52
  194. package/dist/internal/store-mirror.d.ts +2 -2
  195. package/dist/internal/store-mirror.js +2 -2
  196. package/dist/internal/tenant-slack/relay.d.ts +2 -0
  197. package/dist/internal/tenant-slack/relay.d.ts.map +1 -1
  198. package/dist/internal/tenant-slack/relay.js +18 -8
  199. package/dist/internal/workspace-sync.d.ts +31 -6
  200. package/dist/internal/workspace-sync.d.ts.map +1 -1
  201. package/dist/internal/workspace-sync.js +67 -12
  202. package/dist/internal/workspace.d.ts +9 -0
  203. package/dist/internal/workspace.d.ts.map +1 -1
  204. package/dist/internal/workspace.js +16 -0
  205. package/dist/playground/assets/index-Bq2HpEQB.js +67 -0
  206. package/dist/playground/assets/index-CZKKNlmb.css +1 -0
  207. package/dist/playground/index.html +2 -2
  208. package/dist/reminders.d.ts +24 -5
  209. package/dist/reminders.d.ts.map +1 -1
  210. package/dist/reminders.js +28 -5
  211. package/dist/types.d.ts +98 -28
  212. package/dist/types.d.ts.map +1 -1
  213. package/docs/README.md +6 -1
  214. package/docs/guides/grokbot-agents.md +93 -0
  215. package/docs/guides/opentelemetry.md +3 -4
  216. package/docs/reference/channels.md +11 -19
  217. package/docs/reference/cli.md +7 -3
  218. package/docs/reference/extensions.md +2 -0
  219. package/docs/templates/grokbot-agents.md +53 -0
  220. package/package.json +12 -3
  221. package/skills/otel/SKILL.md +3 -3
  222. package/src/bin/agent-serve.ts +1 -9
  223. package/src/channels/bitbucket/types.ts +2 -4
  224. package/src/channels/deployments/deployments-channel.ts +1 -0
  225. package/src/channels/deployments/types.ts +7 -8
  226. package/src/channels/github/types.ts +2 -4
  227. package/src/channels/gitlab/types.ts +2 -5
  228. package/src/channels/origin/types.ts +2 -3
  229. package/src/channels/slack/defaults.ts +3 -0
  230. package/src/channels/slack/dispatch.ts +1 -0
  231. package/src/channels/slack/live-delivery.ts +53 -12
  232. package/src/channels/slack/types.ts +4 -3
  233. package/src/files.ts +9 -2
  234. package/src/index.ts +6 -3
  235. package/src/internal/cli-deploy.ts +30 -12
  236. package/src/internal/cursor/backend-client.ts +90 -2
  237. package/src/internal/cursor-agent-template.ts +1 -0
  238. package/src/internal/deploy-client.ts +16 -0
  239. package/src/internal/deploy-manifest.ts +16 -11
  240. package/src/internal/discovery/agent.ts +1 -0
  241. package/src/internal/discovery/info.ts +6 -0
  242. package/src/internal/discovery/modules.ts +2 -4
  243. package/src/internal/discovery/project.ts +3 -0
  244. package/src/internal/discovery/reminders.ts +65 -0
  245. package/src/internal/discovery/subagent.ts +1 -0
  246. package/src/internal/distribution.ts +20 -0
  247. package/src/internal/framework-file-storage.ts +3 -1
  248. package/src/internal/framework-storage-selection.ts +43 -6
  249. package/src/internal/guest-network.ts +3 -0
  250. package/src/internal/hosted-delivery-protocol.ts +96 -0
  251. package/src/internal/hosted-delivery.ts +207 -28
  252. package/src/internal/hosted-managed-automation.ts +49 -5
  253. package/src/internal/init-project.ts +4 -1
  254. package/src/internal/local-control-plane.ts +281 -22
  255. package/src/internal/reminder-control-plane-protocol.ts +499 -0
  256. package/src/internal/reminder-runner.ts +421 -48
  257. package/src/internal/reminder-schedule.ts +11 -6
  258. package/src/internal/reminder-store.ts +27 -7
  259. package/src/internal/request-error-status.ts +27 -3
  260. package/src/internal/scm/pr-url.ts +167 -20
  261. package/src/internal/sdk-runner.ts +19 -0
  262. package/src/internal/server.ts +85 -16
  263. package/src/internal/session-engine.ts +173 -56
  264. package/src/internal/store-mirror.ts +2 -2
  265. package/src/internal/tenant-slack/relay.ts +28 -4
  266. package/src/internal/workspace-sync.ts +84 -12
  267. package/src/internal/workspace.ts +20 -0
  268. package/src/reminders.ts +35 -4
  269. package/src/types.ts +104 -28
  270. package/templates/grokbot-agents/README.md +26 -0
  271. package/templates/grokbot-agents/agent/agent.ts +6 -0
  272. package/templates/grokbot-agents/agent/extensions/grokbot.ts +5 -0
  273. package/templates/grokbot-agents/agent/instructions.md +7 -0
  274. package/templates/grokbot-agents/evals/evals.config.ts +5 -0
  275. package/templates/grokbot-agents/evals/grokbot-agents.eval.ts +18 -0
  276. package/templates/grokbot-agents/init.json +18 -0
  277. package/templates/grokbot-agents/package.json +17 -0
  278. package/templates/grokbot-agents/tsconfig.json +12 -0
  279. package/dist/docs/assets/chunks/@localSearchIndexroot.Bqsulb9K.js +0 -1
  280. package/dist/docs/assets/index.md.D75GWhPl.js +0 -5
  281. package/dist/docs/assets/index.md.D75GWhPl.lean.js +0 -1
  282. package/dist/playground/assets/index-8YiozU89.js +0 -67
  283. package/dist/playground/assets/index-MbMxXg-y.css +0 -1
  284. /package/dist/docs/assets/{reference_cli.md.CJNc_xYK.lean.js → reference_cli.md.Dm67hd2D.lean.js} +0 -0
  285. /package/dist/docs/assets/{reference_extensions.md.DykHW3qL.lean.js → reference_extensions.md.CGmMLblt.lean.js} +0 -0
  286. /package/dist/docs/assets/{skills_otel.md.CqhobH3B.lean.js → skills_otel.md.B5Ddv1xH.lean.js} +0 -0
@@ -2,6 +2,43 @@ export const HOSTED_DELIVERY_PROTOCOL_VERSION = 2;
2
2
  export const HOSTED_DELIVERY_HEADER = "x-agent-sdk-hosted-delivery";
3
3
  export const HOSTED_ADMISSION_PATH = "/v1/internal/hosted-admission";
4
4
  export const HOSTED_EXECUTION_PATH = "/v1/internal/hosted-execution";
5
+ export const HOSTED_GUEST_RETRY_TRANSIENT = "transient";
6
+ export const HOSTED_GUEST_RETRY_TERMINAL = "terminal";
7
+
8
+ export type HostedGuestRetryDisposition =
9
+ | typeof HOSTED_GUEST_RETRY_TRANSIENT
10
+ | typeof HOSTED_GUEST_RETRY_TERMINAL;
11
+
12
+ export type HostedGuestError = {
13
+ ok: false;
14
+ error: string;
15
+ retry: HostedGuestRetryDisposition;
16
+ message?: string;
17
+ turnStatus?: string;
18
+ };
19
+
20
+ /**
21
+ * Hosted delivery is the only HTTP surface whose failures drive Temporal
22
+ * retries. Keep its retry disposition explicit instead of making the shared
23
+ * HTTP error helper guess from a status code.
24
+ */
25
+ export function hostedGuestErrorResponse(input: {
26
+ status: number;
27
+ error: string;
28
+ retry: HostedGuestRetryDisposition;
29
+ message?: string;
30
+ turnStatus?: string;
31
+ }): Response {
32
+ const body: HostedGuestError = {
33
+ ok: false,
34
+ error: input.error,
35
+ retry: input.retry,
36
+ message: input.message,
37
+ turnStatus: input.turnStatus,
38
+ };
39
+ return Response.json(body, { status: input.status });
40
+ }
41
+
5
42
  /**
6
43
  * Filename under the serve `--state-root` (not the per-slug SessionEngine
7
44
  * dir). Hosted freeze uses `/workspace/.agent-serve`; the Temporal host
@@ -10,6 +47,25 @@ export const HOSTED_EXECUTION_PATH = "/v1/internal/hosted-execution";
10
47
  */
11
48
  export const HOSTED_EXECUTION_DIAG_FILENAME = "hosted-execution.json";
12
49
 
50
+ /**
51
+ * Reserved hosted-admission `channelKind` for durable reminder fires.
52
+ * Bypasses authored channel admission and invokes ReminderRunner.dispatch.
53
+ * Backend builds envelopes with this constant + {@link HOSTED_REMINDER_EVENT_TYPE}.
54
+ */
55
+ export const HOSTED_REMINDER_CHANNEL_KIND = "agent-sdk:reminder";
56
+
57
+ /**
58
+ * Reserved hosted-admission `eventType` for durable reminder fires.
59
+ * Payload is {@link HostedReminderFirePayload}.
60
+ */
61
+ export const HOSTED_REMINDER_EVENT_TYPE = "agent-sdk.reminder/fire";
62
+
63
+ /** Compact reminder-fire payload on the reserved hosted-admission path. */
64
+ export type HostedReminderFirePayload = {
65
+ reminderId: string;
66
+ fireCount: number;
67
+ };
68
+
13
69
  export type HostedAdmissionManagedAutomation = {
14
70
  automationUuid: string;
15
71
  mcpServerNames: string[];
@@ -171,6 +227,46 @@ export function parseHostedExecution(
171
227
  return body as HostedExecution;
172
228
  }
173
229
 
230
+ /**
231
+ * True when the admission envelope is the reserved internal reminder fire
232
+ * path (not an authored channel event).
233
+ */
234
+ export function isHostedReminderAdmission(delivery: HostedAdmission): boolean {
235
+ return (
236
+ delivery.channelKind === HOSTED_REMINDER_CHANNEL_KIND &&
237
+ delivery.eventType === HOSTED_REMINDER_EVENT_TYPE
238
+ );
239
+ }
240
+
241
+ /**
242
+ * Parse `{ reminderId, fireCount }` from a reserved reminder admission
243
+ * payload. Rejects unknown keys and non-integer fireCount.
244
+ */
245
+ export function parseHostedReminderFirePayload(
246
+ value: unknown
247
+ ): HostedReminderFirePayload | undefined {
248
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
249
+ return undefined;
250
+ }
251
+ const body = value as Record<string, unknown>;
252
+ const keys = Object.keys(body);
253
+ if (
254
+ keys.length !== 2 ||
255
+ !Object.hasOwn(body, "reminderId") ||
256
+ !Object.hasOwn(body, "fireCount") ||
257
+ !boundedString(body.reminderId, 128) ||
258
+ typeof body.fireCount !== "number" ||
259
+ !Number.isInteger(body.fireCount) ||
260
+ body.fireCount < 0
261
+ ) {
262
+ return undefined;
263
+ }
264
+ return {
265
+ reminderId: body.reminderId,
266
+ fireCount: body.fireCount,
267
+ };
268
+ }
269
+
174
270
  export function parseHostedAdmissionOutcome(
175
271
  value: unknown
176
272
  ): HostedAdmissionOutcome | undefined {
@@ -36,9 +36,15 @@ import {
36
36
  HOSTED_DELIVERY_HEADER,
37
37
  HOSTED_DELIVERY_PROTOCOL_VERSION,
38
38
  HOSTED_EXECUTION_PATH,
39
+ HOSTED_GUEST_RETRY_TERMINAL,
40
+ HOSTED_GUEST_RETRY_TRANSIENT,
39
41
  type HostedAdmission,
42
+ type HostedGuestRetryDisposition,
43
+ hostedGuestErrorResponse,
44
+ isHostedReminderAdmission,
40
45
  parseHostedAdmission,
41
46
  parseHostedExecution,
47
+ parseHostedReminderFirePayload,
42
48
  } from "./hosted-delivery-protocol.js";
43
49
  import {
44
50
  abortReasonFromTurnStatus,
@@ -50,9 +56,13 @@ import {
50
56
  type HostedExecutionFlushSinks,
51
57
  } from "./hosted-execution-flush.js";
52
58
  import { recordHostedManagedAutomation } from "./hosted-managed-automation.js";
53
- import { errorResponse, readJsonObject } from "./http-channel.js";
59
+ import { readJsonObject } from "./http-channel.js";
54
60
  import type { LogRingEntry } from "./log-ring.js";
55
61
  import { endActiveHttpSpan } from "./otel/http.js";
62
+ import {
63
+ ReminderValidationError,
64
+ UnknownReminderError,
65
+ } from "./reminder-runner.js";
56
66
  import { statusForThrownRequestError } from "./request-error-status.js";
57
67
  import type { Router } from "./router.js";
58
68
  import type { SessionRunExecutionWrite } from "./session-run-log.js";
@@ -108,6 +118,32 @@ function boundedMessage(text: string): string {
108
118
  : text;
109
119
  }
110
120
 
121
+ function terminalHostedError(
122
+ status: number,
123
+ error: string,
124
+ message?: string
125
+ ): Response {
126
+ return hostedGuestErrorResponse({
127
+ status,
128
+ error,
129
+ retry: HOSTED_GUEST_RETRY_TERMINAL,
130
+ message,
131
+ });
132
+ }
133
+
134
+ function transientHostedError(
135
+ status: number,
136
+ error: string,
137
+ message?: string
138
+ ): Response {
139
+ return hostedGuestErrorResponse({
140
+ status,
141
+ error,
142
+ retry: HOSTED_GUEST_RETRY_TRANSIENT,
143
+ message,
144
+ });
145
+ }
146
+
111
147
  /**
112
148
  * Classify deterministic authored protocol violations as non-retryable 422
113
149
  * admissions. Anything else returns `undefined` so callers fall through to
@@ -126,7 +162,7 @@ function nonRetryableRejection(error: unknown): AdmissionDispatch | undefined {
126
162
  return undefined;
127
163
  }
128
164
  return {
129
- response: errorResponse(
165
+ response: terminalHostedError(
130
166
  422,
131
167
  code,
132
168
  boundedMessage((error as Error).message)
@@ -150,10 +186,7 @@ export async function dispatchHostedAdmission(
150
186
  const adapter = getHostedAdmissionAdapter(input.definition);
151
187
  if (adapter === undefined || adapter.kind !== input.delivery.channelKind) {
152
188
  return {
153
- response: Response.json(
154
- { ok: false, error: "channel_kind_mismatch" },
155
- { status: 422 }
156
- ),
189
+ response: terminalHostedError(422, "channel_kind_mismatch"),
157
190
  };
158
191
  }
159
192
  // The admission window marker follows the async graph into task bodies so
@@ -161,6 +194,70 @@ export async function dispatchHostedAdmission(
161
194
  return runDuringHostedAdmission(() => runAdmission(input, adapter));
162
195
  }
163
196
 
197
+ /**
198
+ * Reserved reminder admission: parse the compact payload and invoke
199
+ * ReminderRunner.dispatch. Returns a standard hosted outcome (`task` /
200
+ * `skip`) and never opens the send-capture / model-session path here —
201
+ * prompt-form fires still follow up inside the runner.
202
+ */
203
+ async function dispatchHostedReminderAdmission(
204
+ input: {
205
+ fireReminder?(
206
+ reminderId: string,
207
+ expectedFireCount: number
208
+ ): Promise<{
209
+ reminderId: string;
210
+ outcome: "fired" | "noop";
211
+ reason?: string;
212
+ }>;
213
+ },
214
+ delivery: HostedAdmission
215
+ ): Promise<Response> {
216
+ if (input.fireReminder === undefined) {
217
+ return transientHostedError(
218
+ 503,
219
+ "reminder_dispatch_unavailable",
220
+ "This guest has no reminder runner wired for hosted admission."
221
+ );
222
+ }
223
+ const payload = parseHostedReminderFirePayload(delivery.payload);
224
+ if (payload === undefined) {
225
+ return terminalHostedError(
226
+ 400,
227
+ "invalid_reminder_payload",
228
+ "Expected reminder payload { reminderId, fireCount }."
229
+ );
230
+ }
231
+ try {
232
+ const result = await input.fireReminder(
233
+ payload.reminderId,
234
+ payload.fireCount
235
+ );
236
+ const outcome = result.outcome === "noop" ? "skip" : "task";
237
+ return Response.json({
238
+ ok: true,
239
+ v: HOSTED_DELIVERY_PROTOCOL_VERSION,
240
+ outcome,
241
+ });
242
+ } catch (error) {
243
+ if (error instanceof UnknownReminderError) {
244
+ return terminalHostedError(
245
+ 404,
246
+ "unknown_reminder",
247
+ boundedMessage(error.message)
248
+ );
249
+ }
250
+ if (error instanceof ReminderValidationError) {
251
+ return terminalHostedError(
252
+ 400,
253
+ "invalid_reminder",
254
+ boundedMessage(error.message)
255
+ );
256
+ }
257
+ throw error;
258
+ }
259
+ }
260
+
164
261
  async function runAdmission(
165
262
  input: DispatchInput,
166
263
  adapter: HostedAdmissionAdapter
@@ -198,9 +295,9 @@ async function runAdmission(
198
295
  }
199
296
  if (!dispatched.ok) {
200
297
  return {
201
- response: Response.json(
202
- { ok: false, error: "channel_dispatch_failed" },
203
- { status: dispatched.status >= 400 ? dispatched.status : 502 }
298
+ response: terminalHostedError(
299
+ dispatched.status >= 400 ? dispatched.status : 502,
300
+ "channel_dispatch_failed"
204
301
  ),
205
302
  };
206
303
  }
@@ -213,7 +310,7 @@ async function runAdmission(
213
310
  return rejected;
214
311
  }
215
312
  return {
216
- response: errorResponse(
313
+ response: terminalHostedError(
217
314
  503,
218
315
  "background_dispatch_failed",
219
316
  boundedMessage(error instanceof Error ? error.message : String(error))
@@ -240,10 +337,7 @@ async function runAdmission(
240
337
  const outcome = dispatchOutcome(dispatched);
241
338
  if (outcome === undefined || outcome === "send") {
242
339
  return {
243
- response: Response.json(
244
- { ok: false, error: "channel_outcome_missing" },
245
- { status: 502 }
246
- ),
340
+ response: terminalHostedError(502, "channel_outcome_missing"),
247
341
  };
248
342
  }
249
343
  return {
@@ -329,6 +423,19 @@ export function registerHostedDeliveryRoute(input: {
329
423
  channelId: string,
330
424
  sessionPublicId?: string
331
425
  ): ChannelHandlerArgs;
426
+ /**
427
+ * Reserved reminder admission: dispatch a hydrated ReminderRunner fire
428
+ * without authored channel admission. Returns the runner's outcome so the
429
+ * route can map fired → task and noop → skip.
430
+ */
431
+ fireReminder?(
432
+ reminderId: string,
433
+ expectedFireCount: number
434
+ ): Promise<{
435
+ reminderId: string;
436
+ outcome: "fired" | "noop";
437
+ reason?: string;
438
+ }>;
332
439
  /**
333
440
  * Await the session's durable mirror (dispatch chain + storage queue)
334
441
  * before the execution reply: the control plane may park the pod the
@@ -358,6 +465,13 @@ export function registerHostedDeliveryRoute(input: {
358
465
  flushStartLog?(startLogId: string): Promise<void>;
359
466
  /** Snapshot of the process log ring at persist time. */
360
467
  snapshotLogs?(): LogRingEntry[];
468
+ /**
469
+ * Drop the cached SDK agent handle before the HTTP reply. Hosted v2
470
+ * hibernates this process as soon as the reply lands; leaving the handle
471
+ * in memory freezes a dead Connect/HTTP2 session that the next wake
472
+ * then reuses.
473
+ */
474
+ evictSdkSession?(sessionId: string): void;
361
475
  /**
362
476
  * Wait until guest egress works before authored admission/execution.
363
477
  * Defaults to {@link waitForGuestNetworkReady}. Tests inject a stub.
@@ -393,7 +507,11 @@ export function registerHostedDeliveryRoute(input: {
393
507
  const consumed = consumeBoundSecrets();
394
508
  return consumed.ok
395
509
  ? undefined
396
- : errorResponse(503, consumed.code, boundedMessage(consumed.message));
510
+ : transientHostedError(
511
+ 503,
512
+ consumed.code,
513
+ boundedMessage(consumed.message)
514
+ );
397
515
  };
398
516
  const finishNetworkWait = async (
399
517
  phase: "admission" | "execution"
@@ -416,7 +534,7 @@ export function registerHostedDeliveryRoute(input: {
416
534
  : "Guest network is not ready for outbound requests.";
417
535
  return {
418
536
  timing,
419
- response: errorResponse(
537
+ response: transientHostedError(
420
538
  503,
421
539
  GUEST_NETWORK_UNAVAILABLE,
422
540
  boundedMessage(message)
@@ -463,23 +581,44 @@ export function registerHostedDeliveryRoute(input: {
463
581
  if (unconsumed !== undefined) {
464
582
  return finish(unconsumed);
465
583
  }
466
- const delivery = parseHostedAdmission(await readJsonObject(request));
584
+ const rawAdmission = await readJsonObject(request);
585
+ const delivery = parseHostedAdmission(rawAdmission);
467
586
  if (delivery === undefined) {
587
+ const rawKeys =
588
+ typeof rawAdmission === "object" &&
589
+ rawAdmission !== null &&
590
+ !Array.isArray(rawAdmission)
591
+ ? Object.keys(rawAdmission as Record<string, unknown>)
592
+ : [];
593
+ console.info(
594
+ `[agent-sdk] hosted admission rejected: envelope failed to parse keys=${JSON.stringify(rawKeys)} hasManagedAutomation=${String(rawKeys.includes("managedAutomation"))}`
595
+ );
468
596
  return finish(
469
- errorResponse(
597
+ terminalHostedError(
470
598
  400,
471
599
  "invalid_hosted_admission",
472
600
  "Expected a supported Agent SDK hosted-admission envelope."
473
601
  )
474
602
  );
475
603
  }
604
+ console.info(
605
+ `[agent-sdk] hosted admission received deliveryId=${delivery.deliveryId} channelId=${delivery.channelId} channelKind=${delivery.channelKind} eventType=${delivery.eventType} sessionMode=${delivery.sessionMode} managedAutomation=${delivery.managedAutomation === undefined ? "<absent>" : `automationUuid=${delivery.managedAutomation.automationUuid} mcpServerNames=${String(delivery.managedAutomation.mcpServerNames.length)} slackChannels=${delivery.managedAutomation.slackChannels === undefined ? "<absent>" : JSON.stringify(delivery.managedAutomation.slackChannels)}`}`
606
+ );
476
607
  recordHostedManagedAutomation(delivery);
608
+ if (isHostedReminderAdmission(delivery)) {
609
+ const network = await finishNetworkWait("admission");
610
+ guestNetwork = network.timing;
611
+ if (network.response !== undefined) {
612
+ return finish(network.response);
613
+ }
614
+ return finish(await dispatchHostedReminderAdmission(input, delivery));
615
+ }
477
616
  const channel = input.channels.find(
478
617
  (candidate) => candidate.id === delivery.channelId
479
618
  );
480
619
  if (channel === undefined) {
481
620
  return finish(
482
- errorResponse(
621
+ terminalHostedError(
483
622
  404,
484
623
  "channel_not_found",
485
624
  `No channel named "${delivery.channelId}" is mounted.`
@@ -536,7 +675,7 @@ export function registerHostedDeliveryRoute(input: {
536
675
  const execution = parseHostedExecution(await readJsonObject(request));
537
676
  if (execution === undefined) {
538
677
  return finish(
539
- errorResponse(
678
+ terminalHostedError(
540
679
  400,
541
680
  "invalid_hosted_execution",
542
681
  "Expected a supported Agent SDK hosted-execution envelope."
@@ -547,7 +686,7 @@ export function registerHostedDeliveryRoute(input: {
547
686
  const admitted = pending.get(execution.admissionToken);
548
687
  if (admitted === undefined) {
549
688
  return finish(
550
- errorResponse(
689
+ transientHostedError(
551
690
  409,
552
691
  "hosted_admission_unavailable",
553
692
  "The hosted admission token is missing or expired."
@@ -559,7 +698,7 @@ export function registerHostedDeliveryRoute(input: {
559
698
  admitted.sessionPublicId !== execution.sessionPublicId
560
699
  ) {
561
700
  return finish(
562
- errorResponse(
701
+ transientHostedError(
563
702
  409,
564
703
  "hosted_admission_session_mismatch",
565
704
  "The hosted admission token is already bound to another session."
@@ -624,6 +763,7 @@ export function registerHostedDeliveryRoute(input: {
624
763
  sessionId: "",
625
764
  turnStatus: HOSTED_EXECUTION_DIAG_RUNNING_STATUS,
626
765
  });
766
+ let sessionId = "";
627
767
  try {
628
768
  const args = input.buildHandlerArgs(
629
769
  admitted.send.channelId,
@@ -635,10 +775,19 @@ export function registerHostedDeliveryRoute(input: {
635
775
  key: admitted.send.mailboxContinuationKey,
636
776
  },
637
777
  });
778
+ sessionId = session.id;
638
779
  const outcome = await session.waitForCompletion();
639
780
  // Failed turns drain too: their record/continuation updates must
640
781
  // survive the park just like a finished turn's.
641
782
  await input.drainSessionDurability?.(session.id);
783
+ // Evict before the reply: TAS parks and hibernates this process
784
+ // as soon as the POST returns. A leftover SDK handle freezes a
785
+ // dead Connect/HTTP2 session that the next wake then reuses.
786
+ evictHostedSdkSessions(
787
+ input.evictSdkSession,
788
+ session.id,
789
+ execution.sessionPublicId
790
+ );
642
791
  await writeDiag({
643
792
  sessionId: session.id,
644
793
  turnStatus: outcome.status,
@@ -652,11 +801,15 @@ export function registerHostedDeliveryRoute(input: {
652
801
  // waitForCompletion resolves (does not throw) on a quiet
653
802
  // Connect abort. Map that to guest_connect_stalled so TAS
654
803
  // retries the same pod. Real runner failures stay turn_failed.
804
+ const hostedFailure = hostedFailureForUnfinishedTurn(
805
+ outcome.errorMessage
806
+ );
655
807
  return {
656
808
  status: 503,
657
809
  body: {
658
810
  ok: false,
659
- error: hostedErrorForUnfinishedTurn(outcome.errorMessage),
811
+ error: hostedFailure.error,
812
+ retry: hostedFailure.retry,
660
813
  turnStatus: outcome.status,
661
814
  message: outcome.errorMessage,
662
815
  },
@@ -671,6 +824,11 @@ export function registerHostedDeliveryRoute(input: {
671
824
  },
672
825
  };
673
826
  } catch (error) {
827
+ evictHostedSdkSessions(
828
+ input.evictSdkSession,
829
+ sessionId,
830
+ execution.sessionPublicId
831
+ );
674
832
  await writeDiag({
675
833
  sessionId: "",
676
834
  turnStatus: "error",
@@ -687,16 +845,37 @@ export function registerHostedDeliveryRoute(input: {
687
845
  });
688
846
  }
689
847
 
690
- function hostedErrorForUnfinishedTurn(
691
- errorMessage: string | undefined
692
- ): typeof GUEST_CONNECT_STALLED | "turn_failed" {
848
+ function evictHostedSdkSessions(
849
+ evict: ((sessionId: string) => void) | undefined,
850
+ ...ids: Array<string | undefined>
851
+ ): void {
852
+ if (evict === undefined) {
853
+ return;
854
+ }
855
+ const seen = new Set<string>();
856
+ for (const id of ids) {
857
+ if (id === undefined || id === "" || seen.has(id)) {
858
+ continue;
859
+ }
860
+ seen.add(id);
861
+ evict(id);
862
+ }
863
+ }
864
+
865
+ function hostedFailureForUnfinishedTurn(errorMessage: string | undefined): {
866
+ error: typeof GUEST_CONNECT_STALLED | "turn_failed";
867
+ retry: HostedGuestRetryDisposition;
868
+ } {
693
869
  if (
694
870
  errorMessage !== undefined &&
695
871
  isQuietGuestConnectStallMessage(errorMessage)
696
872
  ) {
697
- return GUEST_CONNECT_STALLED;
873
+ return {
874
+ error: GUEST_CONNECT_STALLED,
875
+ retry: HOSTED_GUEST_RETRY_TRANSIENT,
876
+ };
698
877
  }
699
- return "turn_failed";
878
+ return { error: "turn_failed", retry: HOSTED_GUEST_RETRY_TERMINAL };
700
879
  }
701
880
 
702
881
  async function afterHostedWork<T>(
@@ -17,10 +17,36 @@
17
17
 
18
18
  import type { HostedAdmissionManagedAutomation } from "./hosted-delivery-protocol.js";
19
19
 
20
- const managedAutomationByDelivery = new Map<
21
- string,
22
- { managedAutomation: HostedAdmissionManagedAutomation; expiresAt: number }
23
- >();
20
+ type ManagedAutomationEntry = {
21
+ managedAutomation: HostedAdmissionManagedAutomation;
22
+ expiresAt: number;
23
+ };
24
+
25
+ /**
26
+ * Process-wide slot for the table. Hosted engines run the compiled CLI
27
+ * (`dist/`), which records at admission, while first-party factory agents
28
+ * relative-import this file from `src/` and read at finalize — two module
29
+ * instances in one process. A module-local Map would be recorded in one
30
+ * copy and read from the other (always undefined, so a fork never sees its
31
+ * Slack channels or MCP servers); the shared symbol keeps one table.
32
+ */
33
+ const MANAGED_AUTOMATION_TABLE_KEY = Symbol.for(
34
+ "cursor.agentkit.hostedManagedAutomationByDelivery"
35
+ );
36
+
37
+ function managedAutomationTable(): Map<string, ManagedAutomationEntry> {
38
+ const slots = globalThis as unknown as Record<
39
+ symbol,
40
+ Map<string, ManagedAutomationEntry> | undefined
41
+ >;
42
+ let table = slots[MANAGED_AUTOMATION_TABLE_KEY];
43
+ if (table === undefined) {
44
+ table = new Map();
45
+ slots[MANAGED_AUTOMATION_TABLE_KEY] = table;
46
+ }
47
+ return table;
48
+ }
49
+
24
50
  /** Long enough to outlive a slow review run kicked off by the delivery. */
25
51
  const MANAGED_AUTOMATION_TTL_MS = 60 * 60_000;
26
52
  const MANAGED_AUTOMATION_MAX_ENTRIES = 10_000;
@@ -30,8 +56,12 @@ export function recordHostedManagedAutomation(delivery: {
30
56
  managedAutomation?: HostedAdmissionManagedAutomation;
31
57
  }): void {
32
58
  if (delivery.managedAutomation === undefined) {
59
+ console.info(
60
+ `[agent-sdk] hosted managedAutomation not recorded deliveryId=${delivery.deliveryId}: admission envelope carried no managedAutomation slice (non-managed delivery, or the control plane resolved no MCP servers and no Slack channels)`
61
+ );
33
62
  return;
34
63
  }
64
+ const managedAutomationByDelivery = managedAutomationTable();
35
65
  const now = Date.now();
36
66
  for (const [key, entry] of managedAutomationByDelivery) {
37
67
  if (entry.expiresAt <= now) {
@@ -39,12 +69,19 @@ export function recordHostedManagedAutomation(delivery: {
39
69
  }
40
70
  }
41
71
  if (managedAutomationByDelivery.size >= MANAGED_AUTOMATION_MAX_ENTRIES) {
72
+ console.info(
73
+ `[agent-sdk] hosted managedAutomation table full (${String(managedAutomationByDelivery.size)} entries); clearing before recording deliveryId=${delivery.deliveryId}`
74
+ );
42
75
  managedAutomationByDelivery.clear();
43
76
  }
44
77
  managedAutomationByDelivery.set(delivery.deliveryId, {
45
78
  managedAutomation: delivery.managedAutomation,
46
79
  expiresAt: now + MANAGED_AUTOMATION_TTL_MS,
47
80
  });
81
+ const slackChannels = delivery.managedAutomation.slackChannels;
82
+ console.info(
83
+ `[agent-sdk] hosted managedAutomation recorded deliveryId=${delivery.deliveryId} automationUuid=${delivery.managedAutomation.automationUuid} mcpServerNames=${String(delivery.managedAutomation.mcpServerNames.length)} slackChannels=${slackChannels === undefined ? "<absent>" : JSON.stringify(slackChannels)} ttlMs=${String(MANAGED_AUTOMATION_TTL_MS)} tableSize=${String(managedAutomationByDelivery.size)}`
84
+ );
48
85
  }
49
86
 
50
87
  /**
@@ -55,11 +92,18 @@ export function recordHostedManagedAutomation(delivery: {
55
92
  export function getHostedManagedAutomation(
56
93
  deliveryId: string
57
94
  ): HostedAdmissionManagedAutomation | undefined {
95
+ const managedAutomationByDelivery = managedAutomationTable();
58
96
  const entry = managedAutomationByDelivery.get(deliveryId);
59
97
  if (entry === undefined) {
98
+ console.info(
99
+ `[agent-sdk] hosted managedAutomation lookup miss deliveryId=${deliveryId}: no entry (never recorded in this process, or evicted) tableSize=${String(managedAutomationByDelivery.size)} knownDeliveryIds=${JSON.stringify([...managedAutomationByDelivery.keys()].slice(0, 10))}`
100
+ );
60
101
  return undefined;
61
102
  }
62
103
  if (entry.expiresAt <= Date.now()) {
104
+ console.info(
105
+ `[agent-sdk] hosted managedAutomation lookup expired deliveryId=${deliveryId} automationUuid=${entry.managedAutomation.automationUuid} expiredMsAgo=${String(Date.now() - entry.expiresAt)}`
106
+ );
63
107
  managedAutomationByDelivery.delete(deliveryId);
64
108
  return undefined;
65
109
  }
@@ -68,5 +112,5 @@ export function getHostedManagedAutomation(
68
112
 
69
113
  /** Drop recorded managed-automation slices (tests only). */
70
114
  export function resetHostedManagedAutomationForTest(): void {
71
- managedAutomationByDelivery.clear();
115
+ managedAutomationTable().clear();
72
116
  }
@@ -77,6 +77,7 @@ const TEMPLATES: Readonly<Record<TemplateName, TemplateEntry>> = {
77
77
  "agents-md": { dir: "agents-md" },
78
78
  "code-wiki": { dir: "code-wiki" },
79
79
  demo: { dir: "demo" },
80
+ "grokbot-agents": { dir: "grokbot-agents" },
80
81
  "pr-autofixer": { dir: "pr-autofixer" },
81
82
  "security-help": { dir: "security-help" },
82
83
  "security-reviewer": { dir: "security-reviewer" },
@@ -711,6 +712,7 @@ export function printInitGuide(): void {
711
712
  Scaffold a project, then open the playground:
712
713
  npx ${PACKAGE_NAME} init ./my-agent # installs deps + links agent-sdk onto PATH
713
714
  npx ${PACKAGE_NAME} init ./my-demo --template demo # record a PR walkthrough
715
+ npx ${PACKAGE_NAME} init ./grokbot --template grokbot-agents # talk to Grok Bot agents
714
716
  npx ${PACKAGE_NAME} init ./code-wiki --template code-wiki # keep wiki pages current after merge
715
717
  npx ${PACKAGE_NAME} init ./agents-md --template agents-md # keep AGENTS.md current from last week's PRs and Slack
716
718
  npx ${PACKAGE_NAME} init ./my-reviewer --template security-reviewer # review PRs for security bugs
@@ -719,8 +721,9 @@ Scaffold a project, then open the playground:
719
721
  npx ${PACKAGE_NAME} init ./my-triage --template triage-jira # comment on Jira issues
720
722
  npx ${PACKAGE_NAME} init ./my-owners --template agentic-owners # review PRs via owners policies
721
723
  npx ${PACKAGE_NAME} init ./pr-autofixer --template pr-autofixer # fix PRs on a cloud VM
722
- # TTY asks for GitHub repos. Scripts pass --var:
724
+ # TTY asks the template's questions. Scripts pass --var:
723
725
  # --var repos=acme/widgets,acme/api
726
+ # --var agents="Plan Keeper, Chief of Staff"
724
727
  cd ./my-agent && agent-sdk dev # or: npx ${PACKAGE_NAME} dev
725
728
 
726
729
  Recommended loop once the project exists (from the project directory):