@cursor/july 0.1.55 → 0.1.61

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 (261) hide show
  1. package/dist/bin/agent-serve.js +30 -23
  2. package/dist/channels/github/github-channel.d.ts +12 -0
  3. package/dist/channels/github/github-channel.d.ts.map +1 -1
  4. package/dist/channels/github/github-channel.js +67 -15
  5. package/dist/channels/github/types.d.ts +27 -1
  6. package/dist/channels/github/types.d.ts.map +1 -1
  7. package/dist/channels/origin/cursor-account.d.ts +22 -0
  8. package/dist/channels/origin/cursor-account.d.ts.map +1 -0
  9. package/dist/channels/origin/cursor-account.js +35 -0
  10. package/dist/channels/origin/events.d.ts +10 -0
  11. package/dist/channels/origin/events.d.ts.map +1 -0
  12. package/dist/channels/origin/events.js +27 -0
  13. package/dist/channels/origin/index.d.ts +29 -0
  14. package/dist/channels/origin/index.d.ts.map +1 -0
  15. package/dist/channels/origin/index.js +28 -0
  16. package/dist/channels/origin/origin-channel.d.ts +68 -0
  17. package/dist/channels/origin/origin-channel.d.ts.map +1 -0
  18. package/dist/channels/origin/origin-channel.js +567 -0
  19. package/dist/channels/origin/origin-webhook.d.ts +38 -0
  20. package/dist/channels/origin/origin-webhook.d.ts.map +1 -0
  21. package/dist/channels/origin/origin-webhook.js +151 -0
  22. package/dist/channels/origin/types.d.ts +152 -0
  23. package/dist/channels/origin/types.d.ts.map +1 -0
  24. package/dist/channels/origin/types.js +1 -0
  25. package/dist/channels/slack/doctor.d.ts +17 -1
  26. package/dist/channels/slack/doctor.d.ts.map +1 -1
  27. package/dist/channels/slack/doctor.js +186 -10
  28. package/dist/docs/404.html +2 -2
  29. package/dist/docs/ab.html +4 -4
  30. package/dist/docs/assets/{app.CVQxhV85.js → app.CW3KJh72.js} +1 -1
  31. package/dist/docs/assets/chunks/@localSearchIndexroot.BuymfBAo.js +1 -0
  32. package/dist/docs/assets/chunks/{VPLocalSearchBox.QAPzJjql.js → VPLocalSearchBox.Bk6EWpPj.js} +1 -1
  33. package/dist/docs/assets/chunks/{theme.CSxTCOFu.js → theme.Bz9AodBA.js} +2 -2
  34. package/dist/docs/assets/{example-agents_fsd.md.DPz9ezO4.js → example-agents_fsd.md.ZeGEpAw_.js} +2 -2
  35. package/dist/docs/assets/{example-agents_fsd.md.DPz9ezO4.lean.js → example-agents_fsd.md.ZeGEpAw_.lean.js} +1 -1
  36. package/dist/docs/assets/{example-agents_security-reviewer.md.Dkf1gyo6.js → example-agents_security-reviewer.md.DBL1TwtP.js} +2 -2
  37. package/dist/docs/assets/{example-agents_security-reviewer.md.Dkf1gyo6.lean.js → example-agents_security-reviewer.md.DBL1TwtP.lean.js} +1 -1
  38. package/dist/docs/assets/guides_convert-automation.md.BhMzTkE5.js +12 -0
  39. package/dist/docs/assets/guides_convert-automation.md.BhMzTkE5.lean.js +1 -0
  40. package/dist/docs/assets/{guides_github.md.B8QKtIpw.js → guides_github.md.CLLQJKRB.js} +4 -4
  41. package/dist/docs/assets/{guides_github.md.B8QKtIpw.lean.js → guides_github.md.CLLQJKRB.lean.js} +1 -1
  42. package/dist/docs/assets/index.md.DhRHS_-L.js +5 -0
  43. package/dist/docs/assets/{index.md.COeoSkcF.lean.js → index.md.DhRHS_-L.lean.js} +1 -1
  44. package/dist/docs/assets/{reference_cli.md.D_CCfG8R.js → reference_cli.md.Cl14Jfo3.js} +8 -2
  45. package/dist/docs/assets/{reference_cli.md.D_CCfG8R.lean.js → reference_cli.md.Cl14Jfo3.lean.js} +1 -1
  46. package/dist/docs/assets/scaffolding-agents.md.CrWSA0Ko.js +1 -0
  47. package/dist/docs/assets/{scaffolding-agents.md.mkc3B_ZW.lean.js → scaffolding-agents.md.CrWSA0Ko.lean.js} +1 -1
  48. package/dist/docs/assets/templates_agentic-owners.md.BkTLORaU.js +14 -0
  49. package/dist/docs/assets/templates_agentic-owners.md.BkTLORaU.lean.js +1 -0
  50. package/dist/docs/assets/templates_demo.md.Bgd6MBaZ.js +4 -0
  51. package/dist/docs/assets/templates_demo.md.Bgd6MBaZ.lean.js +1 -0
  52. package/dist/docs/assets/templates_pr-autofixer.md.DcmoeUNZ.js +8 -0
  53. package/dist/docs/assets/templates_pr-autofixer.md.DcmoeUNZ.lean.js +1 -0
  54. package/dist/docs/assets/templates_security-reviewer.md.C0yIUaYs.js +2 -0
  55. package/dist/docs/assets/templates_security-reviewer.md.C0yIUaYs.lean.js +1 -0
  56. package/dist/docs/building-with-agents.html +4 -4
  57. package/dist/docs/concepts.html +5 -5
  58. package/dist/docs/deployment.html +4 -4
  59. package/dist/docs/evals.html +4 -4
  60. package/dist/docs/example-agents/approval-buddy.html +4 -4
  61. package/dist/docs/example-agents/benny.html +4 -4
  62. package/dist/docs/example-agents/bugbot.html +4 -4
  63. package/dist/docs/example-agents/codebase-wiki.html +4 -4
  64. package/dist/docs/example-agents/codeowners-review.html +4 -4
  65. package/dist/docs/example-agents/concierge.html +4 -4
  66. package/dist/docs/example-agents/fsd.html +5 -5
  67. package/dist/docs/example-agents/index.html +4 -4
  68. package/dist/docs/example-agents/knowledge-base.html +4 -4
  69. package/dist/docs/example-agents/oncall.html +4 -4
  70. package/dist/docs/example-agents/security-reviewer.html +5 -5
  71. package/dist/docs/example-agents/slack-agent.html +4 -4
  72. package/dist/docs/example-agents/weather-agent.html +4 -4
  73. package/dist/docs/guides/agent-to-agent.html +4 -4
  74. package/dist/docs/guides/cloud-runtime.html +4 -4
  75. package/dist/docs/guides/convert-automation.html +36 -0
  76. package/dist/docs/guides/github.html +7 -7
  77. package/dist/docs/guides/human-in-the-loop.html +4 -4
  78. package/dist/docs/guides/mcp-oauth.html +4 -4
  79. package/dist/docs/guides/opentelemetry.html +4 -4
  80. package/dist/docs/guides/slack.html +4 -4
  81. package/dist/docs/guides/webhooks.html +4 -4
  82. package/dist/docs/hashmap.json +1 -1
  83. package/dist/docs/hillclimbing.html +4 -4
  84. package/dist/docs/index.html +6 -6
  85. package/dist/docs/quickstart.html +4 -4
  86. package/dist/docs/reference/agent-config.html +4 -4
  87. package/dist/docs/reference/artifacts.html +4 -4
  88. package/dist/docs/reference/channels.html +4 -4
  89. package/dist/docs/reference/cli.html +12 -6
  90. package/dist/docs/reference/connections.html +4 -4
  91. package/dist/docs/reference/hooks.html +4 -4
  92. package/dist/docs/reference/http-api.html +4 -4
  93. package/dist/docs/reference/instructions.html +4 -4
  94. package/dist/docs/reference/playground.html +4 -4
  95. package/dist/docs/reference/project-layout.html +4 -4
  96. package/dist/docs/reference/prompt.html +4 -4
  97. package/dist/docs/reference/schedules.html +4 -4
  98. package/dist/docs/reference/sessions.html +4 -4
  99. package/dist/docs/reference/skills.html +4 -4
  100. package/dist/docs/reference/subagents.html +4 -4
  101. package/dist/docs/reference/tools.html +4 -4
  102. package/dist/docs/scaffolding-agents.html +5 -5
  103. package/dist/docs/storage.html +4 -4
  104. package/dist/docs/templates/agentic-owners.html +38 -0
  105. package/dist/docs/templates/demo.html +28 -0
  106. package/dist/docs/templates/pr-autofixer.html +32 -0
  107. package/dist/docs/templates/security-reviewer.html +26 -0
  108. package/dist/docs/templates/triage.html +5 -5
  109. package/dist/docs/troubleshooting.html +4 -4
  110. package/dist/index.d.ts +3 -3
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/index.js +2 -2
  113. package/dist/internal/cli-ax.d.ts +2 -0
  114. package/dist/internal/cli-ax.d.ts.map +1 -1
  115. package/dist/internal/cli-ax.js +20 -0
  116. package/dist/internal/cli-slack.d.ts +2 -0
  117. package/dist/internal/cli-slack.d.ts.map +1 -1
  118. package/dist/internal/cli-slack.js +11 -2
  119. package/dist/internal/cursor-event-relay.d.ts +59 -11
  120. package/dist/internal/cursor-event-relay.d.ts.map +1 -1
  121. package/dist/internal/cursor-event-relay.js +133 -26
  122. package/dist/internal/discovery.d.ts.map +1 -1
  123. package/dist/internal/discovery.js +11 -2
  124. package/dist/internal/distribution.d.ts.map +1 -1
  125. package/dist/internal/distribution.js +1 -0
  126. package/dist/internal/handleAgentServeTrigger.d.ts +33 -6
  127. package/dist/internal/handleAgentServeTrigger.d.ts.map +1 -1
  128. package/dist/internal/handleAgentServeTrigger.js +97 -19
  129. package/dist/internal/init-interview.d.ts +67 -0
  130. package/dist/internal/init-interview.d.ts.map +1 -0
  131. package/dist/internal/init-interview.js +300 -0
  132. package/dist/internal/init-project.d.ts +4 -0
  133. package/dist/internal/init-project.d.ts.map +1 -1
  134. package/dist/internal/init-project.js +40 -16
  135. package/dist/internal/mcp-endpoint.d.ts +7 -0
  136. package/dist/internal/mcp-endpoint.d.ts.map +1 -1
  137. package/dist/internal/mcp-endpoint.js +7 -0
  138. package/dist/internal/server.d.ts.map +1 -1
  139. package/dist/internal/server.js +159 -57
  140. package/dist/internal/session-engine.d.ts.map +1 -1
  141. package/dist/internal/session-engine.js +20 -21
  142. package/dist/internal/session-links.d.ts +14 -0
  143. package/dist/internal/session-links.d.ts.map +1 -0
  144. package/dist/internal/session-links.js +69 -0
  145. package/dist/internal/sessions-client.d.ts.map +1 -1
  146. package/dist/internal/sessions-client.js +1 -0
  147. package/dist/playground/assets/index-ClbuaLpm.css +1 -0
  148. package/dist/playground/assets/{index-0oqXUkrR.js → index-SqkR13k_.js} +39 -39
  149. package/dist/playground/index.html +2 -2
  150. package/dist/types.d.ts +19 -12
  151. package/dist/types.d.ts.map +1 -1
  152. package/docs/README.md +15 -0
  153. package/docs/example-agents/fsd.md +3 -0
  154. package/docs/example-agents/security-reviewer.md +3 -0
  155. package/docs/guides/convert-automation.md +176 -0
  156. package/docs/guides/github.md +6 -2
  157. package/docs/reference/cli.md +34 -10
  158. package/docs/scaffolding-agents.md +3 -0
  159. package/docs/templates/agentic-owners.md +97 -0
  160. package/docs/templates/demo.md +84 -0
  161. package/docs/templates/pr-autofixer.md +136 -0
  162. package/docs/templates/security-reviewer.md +89 -0
  163. package/package.json +9 -1
  164. package/skills/github/SKILL.md +4 -5
  165. package/src/bin/agent-serve.ts +13 -6
  166. package/src/channels/github/github-channel.ts +95 -18
  167. package/src/channels/github/types.ts +31 -0
  168. package/src/channels/origin/cursor-account.ts +64 -0
  169. package/src/channels/origin/events.ts +41 -0
  170. package/src/channels/origin/index.ts +29 -0
  171. package/src/channels/origin/origin-channel.ts +784 -0
  172. package/src/channels/origin/origin-webhook.ts +202 -0
  173. package/src/channels/origin/types.ts +186 -0
  174. package/src/channels/slack/doctor.ts +218 -5
  175. package/src/index.ts +3 -1
  176. package/src/internal/cli-ax.ts +23 -0
  177. package/src/internal/cli-slack.ts +11 -1
  178. package/src/internal/cursor-event-relay.ts +193 -31
  179. package/src/internal/discovery.ts +15 -5
  180. package/src/internal/distribution.ts +1 -0
  181. package/src/internal/handleAgentServeTrigger.ts +129 -19
  182. package/src/internal/init-interview.ts +384 -0
  183. package/src/internal/init-project.ts +70 -15
  184. package/src/internal/mcp-endpoint.ts +7 -0
  185. package/src/internal/server.ts +188 -58
  186. package/src/internal/session-engine.ts +5 -21
  187. package/src/internal/session-links.ts +88 -0
  188. package/src/internal/sessions-client.ts +1 -0
  189. package/src/types.ts +19 -12
  190. package/templates/agentic-owners/README.md +73 -0
  191. package/templates/agentic-owners/agent/agent.ts +15 -0
  192. package/templates/agentic-owners/agent/channels/github.ts +85 -0
  193. package/templates/agentic-owners/agent/instructions.md +34 -0
  194. package/templates/agentic-owners/agent/lib/config.ts +13 -0
  195. package/templates/agentic-owners/agent/lib/github.ts +241 -0
  196. package/templates/agentic-owners/agent/lib/owners/README.md +50 -0
  197. package/templates/agentic-owners/agent/lib/owners/constants.ts +22 -0
  198. package/templates/agentic-owners/agent/lib/owners/decision.ts +485 -0
  199. package/templates/agentic-owners/agent/lib/owners/handles.ts +54 -0
  200. package/templates/agentic-owners/agent/lib/owners/match.ts +177 -0
  201. package/templates/agentic-owners/agent/lib/owners/matching.ts +95 -0
  202. package/templates/agentic-owners/agent/lib/owners/parse.ts +589 -0
  203. package/templates/agentic-owners/agent/lib/owners/policyMode.ts +65 -0
  204. package/templates/agentic-owners/agent/lib/owners/prompt.ts +66 -0
  205. package/templates/agentic-owners/agent/lib/owners/prompts/base-review.md +105 -0
  206. package/templates/agentic-owners/agent/lib/owners/types.ts +45 -0
  207. package/templates/agentic-owners/agent/lib/review.ts +777 -0
  208. package/templates/agentic-owners/agent/tools/record_review.ts +69 -0
  209. package/templates/agentic-owners/evals/evals.config.ts +5 -0
  210. package/templates/agentic-owners/evals/owners.eval.ts +116 -0
  211. package/templates/agentic-owners/package.json +20 -0
  212. package/templates/agentic-owners/tsconfig.json +12 -0
  213. package/templates/demo/README.md +33 -0
  214. package/templates/demo/agent/agent.ts +15 -0
  215. package/templates/demo/agent/channels/github.ts +50 -0
  216. package/templates/demo/agent/channels/queue.ts +30 -0
  217. package/templates/demo/agent/instructions.md +8 -0
  218. package/templates/demo/agent/lib/collect.ts +78 -0
  219. package/templates/demo/agent/tools/record_demo.ts +40 -0
  220. package/templates/demo/evals/demo.eval.ts +33 -0
  221. package/templates/demo/evals/evals.config.ts +5 -0
  222. package/templates/demo/package.json +18 -0
  223. package/templates/demo/tsconfig.json +12 -0
  224. package/templates/pr-autofixer/README.md +44 -0
  225. package/templates/pr-autofixer/agent/agent.ts +22 -0
  226. package/templates/pr-autofixer/agent/channels/drive.ts +40 -0
  227. package/templates/pr-autofixer/agent/channels/github.ts +167 -0
  228. package/templates/pr-autofixer/agent/channels/slack.ts +17 -0
  229. package/templates/pr-autofixer/agent/hooks/bind-agent.ts +19 -0
  230. package/templates/pr-autofixer/agent/instructions.md +83 -0
  231. package/templates/pr-autofixer/agent/lib/affinity.ts +33 -0
  232. package/templates/pr-autofixer/agent/lib/drive-schemas.ts +15 -0
  233. package/templates/pr-autofixer/agent/lib/drive.ts +79 -0
  234. package/templates/pr-autofixer/agent/lib/merge-watch.ts +123 -0
  235. package/templates/pr-autofixer/agent/lib/pr-state.ts +54 -0
  236. package/templates/pr-autofixer/agent/lib/repos.ts +19 -0
  237. package/templates/pr-autofixer/agent/lib/start-drive.ts +122 -0
  238. package/templates/pr-autofixer/agent/lib/webhook-buffer.ts +225 -0
  239. package/templates/pr-autofixer/agent/lib/webhook-routing.ts +231 -0
  240. package/templates/pr-autofixer/agent/storage.ts +7 -0
  241. package/templates/pr-autofixer/agent/tools/drive_pr.ts +22 -0
  242. package/templates/pr-autofixer/evals/coordinator.eval.ts +16 -0
  243. package/templates/pr-autofixer/evals/evals.config.ts +5 -0
  244. package/templates/pr-autofixer/init.json +25 -0
  245. package/templates/pr-autofixer/package.json +18 -0
  246. package/templates/pr-autofixer/tsconfig.json +12 -0
  247. package/templates/security-reviewer/README.md +31 -0
  248. package/templates/security-reviewer/agent/agent.ts +15 -0
  249. package/templates/security-reviewer/agent/channels/github.ts +46 -0
  250. package/templates/security-reviewer/agent/instructions.md +22 -0
  251. package/templates/security-reviewer/agent/lib/repos.ts +5 -0
  252. package/templates/security-reviewer/agent/tools/post_findings.ts +72 -0
  253. package/templates/security-reviewer/evals/evals.config.ts +5 -0
  254. package/templates/security-reviewer/evals/review.eval.ts +53 -0
  255. package/templates/security-reviewer/init.json +25 -0
  256. package/templates/security-reviewer/package.json +18 -0
  257. package/templates/security-reviewer/tsconfig.json +12 -0
  258. package/dist/docs/assets/chunks/@localSearchIndexroot.BFpWSo6D.js +0 -1
  259. package/dist/docs/assets/index.md.COeoSkcF.js +0 -5
  260. package/dist/docs/assets/scaffolding-agents.md.mkc3B_ZW.js +0 -1
  261. package/dist/playground/assets/index-tHCjJxv4.css +0 -1
@@ -0,0 +1,97 @@
1
+ ---
2
+ title: "Review pull requests with owners policies"
3
+ description: "Scaffold the agent, commit .agentic-owners policies, and let it risk-tier PRs, request the owners, and approve what the policy allows."
4
+ ---
5
+
6
+ # Review pull requests with owners policies
7
+
8
+ This agent reviews every pull request in your repository. It risk-tiers
9
+ the diff, requests the owning team or user as reviewers, and approves
10
+ what your policy allows. Ownership rules live in
11
+ `.agentic-owners/policy.yml` files committed at any depth of the repo;
12
+ the closest policy to a changed file wins, and policies are always read
13
+ from the PR's base ref so a PR cannot exempt itself.
14
+
15
+ ## Scaffold
16
+
17
+ ```bash
18
+ npx @cursor/july init ./owners-agent --template agentic-owners
19
+ ```
20
+
21
+ `init` writes the project, installs dependencies, and puts `agent-sdk`
22
+ on PATH.
23
+
24
+ ## Log in and run
25
+
26
+ Set your repositories in `agent/lib/config.ts` (`repos: ["you/your-repo"]`),
27
+ then:
28
+
29
+ ```bash
30
+ cd owners-agent
31
+ agent-sdk login
32
+ agent-sdk dev
33
+ ```
34
+
35
+ PR events stream through your Cursor account — no webhook or GitHub App
36
+ setup. Open a PR, or replay a real one deterministically (this also works
37
+ with `repos` empty):
38
+
39
+ ```bash
40
+ agent-sdk github replay https://github.com/you/your-repo/pull/123 --dir .
41
+ ```
42
+
43
+ Deploy with `agent-sdk deploy`.
44
+
45
+ ## Policies
46
+
47
+ With no policy files, every PR gets a default risk review: very-low and
48
+ low risk approve, medium and above hold with a comment. Route reviews by
49
+ committing policies:
50
+
51
+ ```yaml
52
+ # .agentic-owners/policy.yml — anywhere in the repo; closest wins.
53
+ # paths are repo-root-relative globs, wherever the policy file lives.
54
+ version: 1
55
+ policies:
56
+ - paths: ["docs/**"]
57
+ always_approve: true
58
+ - paths: ["src/api/**"]
59
+ team: acme/platform # or user: alice
60
+ prompt: api-review.md # optional extra rubric, same directory
61
+ - paths: ["src/billing/**"]
62
+ user: alice
63
+ human_review_required: true # the agent never approves; a person must
64
+ ```
65
+
66
+ `self_review: true` lets a listed owner's own PRs clear their rule.
67
+ `global_exclusions` in the root policy opts paths out entirely.
68
+
69
+ ## What one review does
70
+
71
+ One model turn per PR head assesses the host-fetched diff against the
72
+ base rubric plus any matched rule prompts, then records a verdict with
73
+ `record_review`. The host recomputes the policy from trusted state and
74
+ applies the deterministic decision:
75
+
76
+ - **Approve** when the tier is low and no matched rule demands a human,
77
+ bound to the head SHA.
78
+ - **Request reviewers** otherwise — the policy owners (max 2, never the
79
+ author), plus one status comment the agent keeps updated in place.
80
+
81
+ The model never writes to GitHub. A broken policy file fails closed with
82
+ a comment listing the validation issues.
83
+
84
+ ## Rubric
85
+
86
+ Edit `agent/lib/owners/prompts/base-review.md` for the risk tiers and
87
+ their boundaries. Per-area guidance belongs in policy `prompt:` files
88
+ next to the policy that names them. The next review reads both.
89
+
90
+ ## Evals
91
+
92
+ ```bash
93
+ agent-sdk eval
94
+ ```
95
+
96
+ Three smoke reviews (docs-only, auth deletion, prompt injection). Eval
97
+ sessions skip GitHub writes.
@@ -0,0 +1,84 @@
1
+ ---
2
+ title: "Record a walkthrough from a collected PR"
3
+ description: "Scaffold the agent, seed the PR on the host, record a walkthrough, and comment the result."
4
+ ---
5
+
6
+ # Record a walkthrough from a collected PR
7
+
8
+ This agent records a walkthrough for a pull request you already opened.
9
+ The host fetches title, body, and files, writes `pr.md` and `files.md`,
10
+ then starts the turn. The model reads those files. It does not fetch
11
+ the PR.
12
+
13
+ ## Scaffold
14
+
15
+ ```bash
16
+ npx @cursor/july init ./demo-agent --template demo
17
+ ```
18
+
19
+ `init` writes the project, installs dependencies, and puts `agent-sdk`
20
+ on PATH.
21
+
22
+ ## Log in
23
+
24
+ Model turns use your Cursor account.
25
+
26
+ ```bash
27
+ cd demo-agent
28
+ agent-sdk login
29
+ ```
30
+
31
+ The command opens a browser if you have no stored credential.
32
+
33
+ ## Collect the PR
34
+
35
+ The host needs GitHub credentials so it can read the PR and comment:
36
+ `GITHUB_TOKEN`, `GH_TOKEN`, or `gh auth`.
37
+
38
+ In the playground, run `/queue/pr` and paste a PR URL or `owner/repo#N`.
39
+
40
+ ```bash
41
+ curl -X POST http://127.0.0.1:3000/demo-agent/v1/channels/queue/pr \
42
+ -H 'content-type: application/json' \
43
+ -d '{ "pr": "acme/shop#42" }'
44
+ ```
45
+
46
+ The host fetches title, body, and files, writes `pr.md` and `files.md`,
47
+ and starts the turn. Retries coalesce on `pr:owner/repo#N`.
48
+
49
+ GitHub label `demo` or comment `/demo` when you terminate webhooks
50
+ yourself: self-host and set `GITHUB_WEBHOOK_SECRET`. Hosted Cursor
51
+ aliases require `X-Agent-Alias-Token`, which GitHub cannot send.
52
+
53
+ `record_demo` comments on that key. Eval sessions skip the comment.
54
+
55
+ ## First walkthrough
56
+
57
+ ```bash
58
+ agent-sdk dev
59
+ ```
60
+
61
+ Open the playground. Run `/queue/pr` with a PR. The model reads the
62
+ seeded files and calls `record_demo` once. Turns are sandboxed with
63
+ `read` and `grep` only: PR title and body are untrusted.
64
+
65
+ ## Evals
66
+
67
+ One smoke case. The host seeds `pr.md` and `files.md`. No GitHub call.
68
+
69
+ ```bash
70
+ agent-sdk eval
71
+ ```
72
+
73
+ ## Deploy
74
+
75
+ ```bash
76
+ agent-sdk deploy
77
+ ```
78
+
79
+ Run it from the agent's git checkout. It infers repository, ref, path,
80
+ and slug, builds on Cursor-managed hosting, and prints the URL.
81
+ `agent-sdk deployments` shows status.
82
+
83
+ Playground and `/queue/pr` need the alias token. GitHub label and
84
+ `/demo` stay on a self-hosted agent with a webhook secret.
@@ -0,0 +1,136 @@
1
+ ---
2
+ title: "Fix pull requests on a Cursor cloud VM"
3
+ description: "Scaffold the agent, point it at your repos, and opt in to auto-fix a PR."
4
+ ---
5
+
6
+ # Fix pull requests on a Cursor cloud VM
7
+
8
+ This agent coordinates from chat and Slack, then hands each opted-in
9
+ pull request to a Cursor cloud VM with a real checkout. The same cloud
10
+ conversation resumes when you drive the PR again, GitHub reports a
11
+ change on that PR, or a merge-conflict reminder fires.
12
+
13
+ Chat never has the target checkout. `gh` and `git` run on the VM.
14
+ Opening a pull request does not start a session. Drive a PR from the
15
+ playground, Slack, or HTTP to opt in. After that, the agent auto-fixes:
16
+ it pushes verified fixes to the PR head and performs workflow actions.
17
+ It never merges, enables auto-merge, or force-pushes.
18
+
19
+ ## Scaffold
20
+
21
+ On a TTY, `init` asks which GitHub repos to watch. Scripts pass the
22
+ same answer with `--var`:
23
+
24
+ ```bash
25
+ npx @cursor/july init ./pr-autofixer --template pr-autofixer
26
+ npx @cursor/july init ./pr-autofixer --template pr-autofixer \
27
+ --var repos=acme/widgets,acme/api --json
28
+ ```
29
+
30
+ `init` writes the project, installs dependencies, and puts `agent-sdk`
31
+ on PATH. You can still edit `agent/lib/repos.ts` later, or override the
32
+ list with `PR_AUTOFIXER_REPOS`.
33
+
34
+ ## Log in
35
+
36
+ Model turns and cloud agents use your Cursor account.
37
+
38
+ ```bash
39
+ cd pr-autofixer
40
+ agent-sdk login
41
+ ```
42
+
43
+ The command opens a browser if you have no stored credential. Cloud
44
+ turns spend cloud-agent budget under that account.
45
+
46
+ ## Point it at a repo
47
+
48
+ `init` writes the repo list into `agent/lib/repos.ts`. One owner. Up to
49
+ 20 repos. The GitHub channel requests `contents-write` so the agent can
50
+ push to the PR head.
51
+
52
+ ## First drive
53
+
54
+ ```bash
55
+ agent-sdk dev
56
+ ```
57
+
58
+ Open the playground. Paste a PR URL or `owner/repo#N`. The local
59
+ agent calls `drive_pr`, which attaches the PR to a cloud session and
60
+ returns when that session exists. Autofix continues in the background.
61
+ `bcId` / `agentUrl` are included when already bound.
62
+
63
+ You can also POST:
64
+
65
+ ```bash
66
+ curl -X POST http://127.0.0.1:3000/pr-autofixer/v1/channels/drive \
67
+ -H 'content-type: application/json' \
68
+ -d '{
69
+ "pr": "https://github.com/acme/widgets/pull/1"
70
+ }'
71
+ ```
72
+
73
+ HTTP and `drive_pr` both return when the session exists, not when
74
+ triage finishes. `bcId` / `agentUrl` are included when already bound.
75
+
76
+ A merged or closed PR returns `status: "finished"` and does not start
77
+ a session.
78
+
79
+ The VM starts from the PR base. The agent creates `autofix/pr-<N>` off
80
+ the PR head the first time it needs code, then pushes verified fixes
81
+ with `git push origin HEAD:<headRef>`. Workflow actions run through
82
+ `gh`. `autoCreatePR` is off, so the agent never opens a new PR.
83
+
84
+ ## GitHub wakes
85
+
86
+ Mounted at `/v1/channels/github`. Cursor relays pull request, comment,
87
+ review, check, and failing status events for the repos you listed. A
88
+ wake only starts or resumes a cloud conversation after that PR has been
89
+ driven. `pull_request.opened` is ignored. A PR comment or review on an
90
+ opted-in PR wakes the agent. A comment on a plain GitHub issue does
91
+ not. The channel buffers about 3 seconds per PR. Payload details are
92
+ dropped on purpose. The follow-up says something changed.
93
+
94
+ Pending wakes snapshot to `host.kv` (`webhook-buffer`) before the
95
+ webhook is ACKed, and restore on restart. Affinity is
96
+ `affinity/{owner/repo#N}` → `bc-…` in the same store, written from
97
+ `agent.bound`. `agent/storage.ts` uses `cursorHostedStorage`, so both
98
+ survive host replace. Local serve without that plug-in falls back to
99
+ `--state-root/kv`.
100
+
101
+ Closing a PR cancels its merge-conflict reminder and drops buffered
102
+ wakes.
103
+
104
+ See [GitHub](../guides/github.md) for `cursorAccount` login and
105
+ fixture replay.
106
+
107
+ ## Slack
108
+
109
+ `agent/channels/slack.ts` uses your signed-in Cursor account. Mention
110
+ the agent or DM it with a PR URL. Same `drive_pr` path as the
111
+ playground. See [Slack](../guides/slack.md).
112
+
113
+ ## Evals
114
+
115
+ One smoke case. Chat without a PR must not call `drive_pr`, so a
116
+ routine eval cannot spawn a cloud agent.
117
+
118
+ ```bash
119
+ agent-sdk eval
120
+ ```
121
+
122
+ Do not add cases that pass a PR URL unless you intend to spend cloud
123
+ budget.
124
+
125
+ ## Deploy
126
+
127
+ ```bash
128
+ agent-sdk deploy
129
+ ```
130
+
131
+ Run it from the agent's git checkout. It infers repository, ref, path,
132
+ and slug, builds on Cursor-managed hosting, and prints the URL.
133
+ `agent-sdk deployments` shows status.
134
+
135
+ See [Cloud runtime](../guides/cloud-runtime.md) for what changes on
136
+ the VM.
@@ -0,0 +1,89 @@
1
+ ---
2
+ title: "Review pull requests for exploitable bugs"
3
+ description: "Scaffold the agent, pick repos, replay a PR, and deploy."
4
+ ---
5
+
6
+ # Review pull requests for exploitable bugs
7
+
8
+ This agent reads a pull request diff and posts one review comment. It
9
+ reports exploitable bugs: injection, authz bypass, secret leaks, SSRF,
10
+ RCE. Style nits stay out.
11
+
12
+ The factory [Security Reviewer](../example-agents/security-reviewer.md)
13
+ runs a staged pipeline with parallel workers. This template is one
14
+ model turn.
15
+
16
+ ## Scaffold
17
+
18
+ ```bash
19
+ npx @cursor/july init ./security-reviewer --template security-reviewer
20
+ ```
21
+
22
+ `init` asks which GitHub repos to watch. Every repo must share one
23
+ owner. Pass `--var repos=acme/api,acme/web` to skip the prompt.
24
+
25
+ The list lands in `agent/lib/repos.ts`. The GitHub channel reads it for
26
+ `cursorAccount` and for the wake filter. Edit that file when the set
27
+ changes.
28
+
29
+ ## Connect GitHub through Cursor
30
+
31
+ Connect GitHub in Cursor for those repositories (Settings or
32
+ [cursor.com/dashboard](https://cursor.com/dashboard)). Sign the host in:
33
+
34
+ ```bash
35
+ cd security-reviewer
36
+ agent-sdk login
37
+ ```
38
+
39
+ `cursorAccount` pulls SCM events from Cursor and mints a short-lived,
40
+ repo-scoped credential. `ctx.host.github` and child `gh` commands share
41
+ it. See the [GitHub guide](../guides/github.md).
42
+
43
+ ## First review
44
+
45
+ ```bash
46
+ agent-sdk dev
47
+ ```
48
+
49
+ `dev` starts the Cursor event relay for the watched repos. To drive a
50
+ known PR without waiting on a live push:
51
+
52
+ ```bash
53
+ agent-sdk github replay https://github.com/acme/api/pull/12 --dir .
54
+ ```
55
+
56
+ `replay` needs pull access. Draft PRs and repos outside
57
+ `agent/lib/repos.ts` are ignored. The channel writes `pr/diff.patch`
58
+ after the wake is acknowledged, then starts a model turn. The model
59
+ calls `post_findings` once.
60
+
61
+ Chat replies stay in the playground. `post_findings` writes the GitHub
62
+ comment.
63
+
64
+ ## What to edit
65
+
66
+ - `agent/lib/repos.ts`: watched repos
67
+ - `agent/instructions.md`: what counts as a finding and the comment
68
+ shape
69
+ - `evals/review.eval.ts`: smoke cases
70
+
71
+ ## Evals
72
+
73
+ Two smoke cases: one XSS fixture and one docs-only change.
74
+
75
+ ```bash
76
+ agent-sdk eval
77
+ ```
78
+
79
+ Eval sessions skip the GitHub write.
80
+
81
+ ## Deploy
82
+
83
+ ```bash
84
+ agent-sdk deploy
85
+ ```
86
+
87
+ Run it from the agent's git checkout. The command infers repository,
88
+ ref, path, and slug. The deployment uses the team's Cursor GitHub
89
+ connection for the same watched repos.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cursor/july",
3
- "version": "0.1.55",
3
+ "version": "0.1.61",
4
4
  "description": "(early alpha) Filesystem-first framework for defining Cursor agents as markdown and TypeScript and serving them over channels with the Cursor SDK.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "repository": {
@@ -70,6 +70,12 @@
70
70
  "import": "./dist/channels/github/index.js",
71
71
  "default": "./dist/channels/github/index.js"
72
72
  },
73
+ "./channels/origin": {
74
+ "anysphere-source": "./src/channels/origin/index.ts",
75
+ "types": "./dist/channels/origin/index.d.ts",
76
+ "import": "./dist/channels/origin/index.js",
77
+ "default": "./dist/channels/origin/index.js"
78
+ },
73
79
  "./skills": {
74
80
  "anysphere-source": "./src/skills.ts",
75
81
  "types": "./dist/skills.d.ts",
@@ -261,6 +267,7 @@
261
267
  "@types/react-dom": "^19.0.0",
262
268
  "@typescript/native-preview": "7.0.0-dev.20260701.1",
263
269
  "@vitejs/plugin-react": "^5.1.2",
270
+ "minimatch": "^10.2.5",
264
271
  "pg": "^8.18.0",
265
272
  "pretty-ms": "^9.2.0",
266
273
  "react": "^19.2.1",
@@ -272,6 +279,7 @@
272
279
  "vite": "^7.3.0",
273
280
  "vitepress": "1.6.4",
274
281
  "vitest": "^4.0.18",
282
+ "yaml": "^2.4.2",
275
283
  "zustand": "^5.0.9"
276
284
  }
277
285
  }
@@ -142,12 +142,11 @@ first real delivery.
142
142
 
143
143
  - **Debounce per PR** (~3s, latest event wins) and re-buffer while CI
144
144
  settles; skip a flush when a turn for that PR is already in flight.
145
- - **Persist the buffer before ACKing** the webhook
146
- (e.g. `.agent-serve/<slug>/webhook-buffer.json`) and restore it on channel
147
- start — a restart must not drop buffered wakes.
145
+ - **Persist the buffer before ACKing** the webhook in `host.kv`, then
146
+ restore it on channel start. A restart must not drop buffered wakes.
148
147
  - **Stable continuation key** `pr:owner/repo#N` so every wake resumes the
149
- PR's session; cross-channel resume needs an affinity store mapping PR →
150
- SDK agent id (write it from an `agent.bound` hook).
148
+ PR's session. Cross-channel resume needs an affinity store mapping PR →
149
+ SDK agent id (write it from an `agent.bound` hook with `ctx.host.kv`).
151
150
  - **Discard payload details in wake prompts** — send a generic "re-check
152
151
  the PR" refresh; the agent re-reads ground truth instead of trusting a
153
152
  stale payload.
@@ -108,7 +108,7 @@ Usage:
108
108
  ${CLI} trajectory --events <file.ndjson> [--text]
109
109
  ${CLI} call <tool> [--input <json>] [--dir <path> | --url <baseUrl> | --prod]
110
110
  [--session <id>] [--slug <slug>] [--team <id>]
111
- ${CLI} init [dir] [--template <name>] [--json]
111
+ ${CLI} init [dir] [--template <name>] [--var id=value]... [--json]
112
112
  ${CLI} convert-automation <url> [--dir <path>] [--json]
113
113
  ${CLI} install-skills [--print] [--json]
114
114
  ${CLI} mcp --prod [--slug <slug>] [--team <id>] [--dir <path>]
@@ -198,9 +198,10 @@ Commands:
198
198
  via POST /v1/tools/:toolName. --session runs it inside an
199
199
  existing session and records it on that session's event stream.
200
200
  init Scaffold a project (skipping existing files), npm install,
201
- run login when unsigned, then print next steps. --json is
202
- machine-readable and never blocks on login. No directory:
203
- print the setup guide.
201
+ run login when unsigned, then print next steps. Templates
202
+ with init.json interview on a TTY; --var answers without a
203
+ prompt. --json is machine-readable and never blocks on
204
+ login. No directory: print the setup guide.
204
205
  convert-automation
205
206
  Export a Cursor Automation into an agentkit project. <url> is
206
207
  the dashboard URL (…/automations/<uuid> or
@@ -481,6 +482,7 @@ async function main(argv: string[]): Promise<number> {
481
482
  options: {
482
483
  dir: { type: "string", default: "." },
483
484
  template: { type: "string" },
485
+ var: { type: "string", multiple: true },
484
486
  port: { type: "string" },
485
487
  host: { type: "string" },
486
488
  mode: { type: "string" },
@@ -540,7 +542,7 @@ async function main(argv: string[]): Promise<number> {
540
542
  org: { type: "string" },
541
543
  "cursor-events": { type: "boolean", default: false },
542
544
  secret: { type: "string" },
543
- channel: { type: "string" },
545
+ channel: { type: "string", multiple: true },
544
546
  install: { type: "boolean", default: false },
545
547
  action: { type: "string" },
546
548
  conclusion: { type: "string" },
@@ -594,6 +596,7 @@ async function main(argv: string[]): Promise<number> {
594
596
  prefix: values.prefix,
595
597
  noPrefix: values["no-prefix"],
596
598
  channelPosts: values["channel-posts"],
599
+ channels: values.channel,
597
600
  slackTeam: values["slack-team"],
598
601
  prod: values.prod,
599
602
  team: values.team,
@@ -620,7 +623,9 @@ async function main(argv: string[]): Promise<number> {
620
623
  return cmdGithub(positionals[0], {
621
624
  dir,
622
625
  slug: values.slug,
623
- channel: values.channel,
626
+ // `--channel` is repeatable for `slack doctor`; the github
627
+ // subcommands target a single channel, so the last one wins.
628
+ channel: values.channel?.at(-1),
624
629
  host: values.host,
625
630
  port,
626
631
  url: values.url,
@@ -646,6 +651,7 @@ async function main(argv: string[]): Promise<number> {
646
651
  dir,
647
652
  initTarget: positionals[0],
648
653
  template: values.template,
654
+ vars: values.var,
649
655
  json: values.json,
650
656
  });
651
657
  }
@@ -1375,6 +1381,7 @@ function axFromOptions(
1375
1381
  tags: partial.tags,
1376
1382
  evalIds: partial.evalIds,
1377
1383
  initTarget: partial.initTarget,
1384
+ vars: partial.vars,
1378
1385
  toolName: partial.toolName,
1379
1386
  toolInput: partial.toolInput,
1380
1387
  url: partial.url,
@@ -136,6 +136,16 @@ const githubPullRequestPayloadSchema: z.ZodType<GitHubPullRequestPayload> =
136
136
  sha: z.string().optional(),
137
137
  }),
138
138
  }),
139
+ changes: z
140
+ .object({
141
+ base: z
142
+ .object({
143
+ ref: z.object({ from: z.string().min(1).optional() }).optional(),
144
+ })
145
+ .optional(),
146
+ })
147
+ .nullable()
148
+ .optional(),
139
149
  sender: senderSchema,
140
150
  installation: installationSchema,
141
151
  label: z
@@ -184,6 +194,32 @@ export function githubContinuationKey(ctx: GitHubParsedContext): string {
184
194
  return `${kind}:${ctx.repository.fullName}#${ctx.conversation.number}`;
185
195
  }
186
196
 
197
+ export interface GitHubPullRequestRef {
198
+ owner: string;
199
+ repo: string;
200
+ number: number;
201
+ }
202
+
203
+ /**
204
+ * Parse a pull-request continuation key minted by
205
+ * {@link githubContinuationKey} back into its repo + number. Undefined for
206
+ * issue keys and non-GitHub sessions — lets a server tool recover which PR
207
+ * its session is pinned to without trusting model-provided identifiers.
208
+ */
209
+ export function parseGitHubPrContinuationKey(
210
+ key: string
211
+ ): GitHubPullRequestRef | undefined {
212
+ const match = /^github-pr:([^/#\s]+)\/([^#\s]+)#(\d+)$/.exec(key);
213
+ if (match === null) {
214
+ return undefined;
215
+ }
216
+ return {
217
+ owner: match[1]!,
218
+ repo: match[2]!,
219
+ number: Number(match[3]!),
220
+ };
221
+ }
222
+
187
223
  /** @deprecated Prefer {@link githubContinuationKey}. */
188
224
  export function githubPullRequestContinuationKey(
189
225
  ctx: GitHubParsedContext
@@ -338,6 +374,9 @@ export function parseGitHubPullRequestEvent(args: {
338
374
  ...(payload.pull_request.base.sha === undefined
339
375
  ? {}
340
376
  : { baseSha: payload.pull_request.base.sha }),
377
+ ...(payload.changes?.base?.ref?.from === undefined
378
+ ? {}
379
+ : { baseRefChangedFrom: payload.changes.base.ref.from }),
341
380
  draft: payload.pull_request.draft ?? false,
342
381
  merged: payload.pull_request.merged === true,
343
382
  ...(payload.pull_request.user?.login === undefined
@@ -1469,15 +1508,34 @@ async function startTurn(input: {
1469
1508
  cloud?: AgentCloudOptions;
1470
1509
  state: GitHubChannelState;
1471
1510
  }): Promise<Response> {
1472
- const session = await input.args.send(input.message, {
1473
- auth: input.dispatch.auth,
1474
- continuationToken: githubContinuationKey(input.ctx),
1475
- title: input.dispatch.title ?? defaultGitHubTitle(input.ctx),
1476
- ...(input.cloud === undefined ? {} : { cloud: input.cloud }),
1477
- state: input.state as unknown as JsonValue,
1478
- // Resume must refresh headSha / refs without wiping sticky banner id.
1479
- refreshState: input.state as unknown as JsonValue,
1480
- });
1511
+ const files = input.dispatch.workspaceFiles;
1512
+ const lazy = typeof files === "function";
1513
+
1514
+ const sendTurn = async () => {
1515
+ const workspaceFiles = lazy ? await files() : files;
1516
+ return input.args.send(input.message, {
1517
+ auth: input.dispatch.auth,
1518
+ continuationToken: githubContinuationKey(input.ctx),
1519
+ title: input.dispatch.title ?? defaultGitHubTitle(input.ctx),
1520
+ ...(input.cloud === undefined ? {} : { cloud: input.cloud }),
1521
+ ...(workspaceFiles === undefined ? {} : { workspaceFiles }),
1522
+ state: input.state as unknown as JsonValue,
1523
+ // Resume must refresh headSha / refs without wiping sticky banner id.
1524
+ refreshState: input.state as unknown as JsonValue,
1525
+ });
1526
+ };
1527
+
1528
+ if (lazy) {
1529
+ scheduleAfterAck(input.args, async () => {
1530
+ await sendTurn();
1531
+ });
1532
+ return Response.json(
1533
+ { ok: true, dispatched: true, mode: "turn" },
1534
+ { status: 202 }
1535
+ );
1536
+ }
1537
+
1538
+ const session = await sendTurn();
1481
1539
  return Response.json({
1482
1540
  ok: true,
1483
1541
  sessionId: session.id,
@@ -1486,22 +1544,41 @@ async function startTurn(input: {
1486
1544
  });
1487
1545
  }
1488
1546
 
1489
- function acknowledgeTask(
1547
+ function reportBackgroundFailure(error: unknown): void {
1548
+ const detail =
1549
+ error instanceof Error ? (error.stack ?? error.message) : String(error);
1550
+ console.error(`[github] background dispatch failed: ${detail}`);
1551
+ }
1552
+
1553
+ function scheduleAfterAck(
1490
1554
  args: ChannelHandlerArgs,
1491
- dispatch: GitHubTaskDispatch,
1492
- extra: Record<string, unknown>
1493
- ): Response {
1494
- // Defer the task past the current turn so the 202 can flush before work
1495
- // starts (and so tests can assert scheduling without racing microtasks).
1555
+ work: () => void | Promise<void>
1556
+ ): void {
1557
+ // Defer past the current turn so the 202 can flush before work starts
1558
+ // (and so tests can assert scheduling without racing microtasks).
1496
1559
  args.waitUntil(
1497
- new Promise<void>((resolve, reject) => {
1560
+ new Promise<void>((resolve) => {
1498
1561
  setImmediate(() => {
1499
1562
  Promise.resolve()
1500
- .then(dispatch.task)
1501
- .then(() => resolve(), reject);
1563
+ .then(work)
1564
+ .then(
1565
+ () => resolve(),
1566
+ (error: unknown) => {
1567
+ reportBackgroundFailure(error);
1568
+ resolve();
1569
+ }
1570
+ );
1502
1571
  });
1503
1572
  })
1504
1573
  );
1574
+ }
1575
+
1576
+ function acknowledgeTask(
1577
+ args: ChannelHandlerArgs,
1578
+ dispatch: GitHubTaskDispatch,
1579
+ extra: Record<string, unknown>
1580
+ ): Response {
1581
+ scheduleAfterAck(args, dispatch.task);
1505
1582
  return Response.json(
1506
1583
  { ok: true, dispatched: true, mode: "task", ...extra },
1507
1584
  { status: 202 }