@cursor/july 0.1.112 → 0.1.113

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 (211) hide show
  1. package/README.md +4 -0
  2. package/dist/bin/agent-serve.js +2 -3
  3. package/dist/channels/checks.d.ts +10 -0
  4. package/dist/channels/checks.d.ts.map +1 -1
  5. package/dist/channels/origin/checks.d.ts +1 -1
  6. package/dist/channels/origin/checks.d.ts.map +1 -1
  7. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  8. package/dist/channels/slack/dispatch.js +6 -2
  9. package/dist/docs/404.html +2 -2
  10. package/dist/docs/assets/{app.DxTdhphC.js → app.CAeK13eM.js} +4 -4
  11. package/dist/docs/assets/chunks/@localSearchIndexroot.Ck9E52Ls.js +1 -0
  12. package/dist/docs/assets/chunks/{VPLocalSearchBox.CR3KTF0X.js → VPLocalSearchBox.C9LbPHod.js} +1 -1
  13. package/dist/docs/assets/chunks/{arc.CVVqBOdS.js → arc.CmMq2zmS.js} +1 -1
  14. package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.CJHGP4ki.js → architectureDiagram-Q4EWVU46.CCXB8Uj5.js} +1 -1
  15. package/dist/docs/assets/chunks/{baseUniq.r7UVVRBP.js → baseUniq.CyQo6eLe.js} +1 -1
  16. package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.DKmMaTre.js → blockDiagram-DXYQGD6D.JYq6w91N.js} +1 -1
  17. package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.DDJsntUO.js → c4Diagram-AHTNJAMY.BRV8GPJJ.js} +1 -1
  18. package/dist/docs/assets/chunks/channel.BHiYmnZ4.js +1 -0
  19. package/dist/docs/assets/chunks/{chunk-4BX2VUAB.BK2rKt6W.js → chunk-4BX2VUAB.Bv4ooYQR.js} +1 -1
  20. package/dist/docs/assets/chunks/{chunk-4TB4RGXK.DRLV8RnF.js → chunk-4TB4RGXK.t4JtKPcj.js} +1 -1
  21. package/dist/docs/assets/chunks/{chunk-55IACEB6.DaKjxtb7.js → chunk-55IACEB6.34lCHj9Y.js} +1 -1
  22. package/dist/docs/assets/chunks/{chunk-EDXVE4YY.C5sPCIT1.js → chunk-EDXVE4YY.BSwrPNrt.js} +1 -1
  23. package/dist/docs/assets/chunks/{chunk-FMBD7UC4.CSGWyNTB.js → chunk-FMBD7UC4.Beeun-R-.js} +1 -1
  24. package/dist/docs/assets/chunks/{chunk-OYMX7WX6.D5tK9XEr.js → chunk-OYMX7WX6.BUUFUcJc.js} +1 -1
  25. package/dist/docs/assets/chunks/{chunk-QZHKN3VN.BeZGd1UZ.js → chunk-QZHKN3VN.B2XjHzN_.js} +1 -1
  26. package/dist/docs/assets/chunks/{chunk-YZCP3GAM.U_tfWwQR.js → chunk-YZCP3GAM.CLYG8znk.js} +1 -1
  27. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.Degh8l90.js +1 -0
  28. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.Degh8l90.js +1 -0
  29. package/dist/docs/assets/chunks/clone.BIywbczV.js +1 -0
  30. package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.DVeRXIb6.js → cose-bilkent-S5V4N54A.DVEa6fZp.js} +1 -1
  31. package/dist/docs/assets/chunks/{dagre-KV5264BT.BpKJAeRZ.js → dagre-KV5264BT.C9PZQK-S.js} +1 -1
  32. package/dist/docs/assets/chunks/{diagram-5BDNPKRD.BQOtrd1Z.js → diagram-5BDNPKRD.DoN0uv3Y.js} +1 -1
  33. package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.CSDAhjPI.js → diagram-G4DWMVQ6.Czv3duqx.js} +1 -1
  34. package/dist/docs/assets/chunks/{diagram-MMDJMWI5.Dpztst2S.js → diagram-MMDJMWI5.BinJ5kWb.js} +1 -1
  35. package/dist/docs/assets/chunks/{diagram-TYMM5635.qJHRizHR.js → diagram-TYMM5635.DW326M4K.js} +1 -1
  36. package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.vbDotH3l.js → erDiagram-SMLLAGMA.U2pR_OA7.js} +1 -1
  37. package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.CqS_ZQr4.js → flowDiagram-DWJPFMVM.ByWJXeYK.js} +1 -1
  38. package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.DTLdR4pN.js → ganttDiagram-T4ZO3ILL.OquF0Rtg.js} +1 -1
  39. package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.D04lnbnr.js → gitGraphDiagram-UUTBAWPF.Bpn01P7X.js} +1 -1
  40. package/dist/docs/assets/chunks/{graph.BlfqLJsM.js → graph.CNRB6ETL.js} +1 -1
  41. package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.tAooImWA.js → infoDiagram-42DDH7IO.CqhknMWi.js} +1 -1
  42. package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.ClUsVqnJ.js → ishikawaDiagram-UXIWVN3A.C6xpR2af.js} +1 -1
  43. package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.C3tUgyCg.js → journeyDiagram-VCZTEJTY.Cg5f7oB3.js} +1 -1
  44. package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.CtD9-QCe.js → kanban-definition-6JOO6SKY.Cx9YTwlU.js} +1 -1
  45. package/dist/docs/assets/chunks/{layout.D38U-LnT.js → layout.ljS-wFtK.js} +1 -1
  46. package/dist/docs/assets/chunks/{linear.BJmssyhN.js → linear.jSxNrsFC.js} +1 -1
  47. package/dist/docs/assets/chunks/{min.DNgXoouU.js → min.Cum8AlQw.js} +1 -1
  48. package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.Dcp6cxeu.js → mindmap-definition-QFDTVHPH.BLiysLpe.js} +1 -1
  49. package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.CLDw6zIs.js → pieDiagram-DEJITSTG.BoIDyuKF.js} +1 -1
  50. package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.CYaeeY4c.js → quadrantDiagram-34T5L4WZ.DLkpDytR.js} +1 -1
  51. package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.gMYuRpq2.js → requirementDiagram-MS252O5E.DqTVqSu2.js} +1 -1
  52. package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.CZqyHFbc.js → sankeyDiagram-XADWPNL6.CG_6FF7j.js} +1 -1
  53. package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.BTsCjUDN.js → sequenceDiagram-FGHM5R23.BIp9602K.js} +1 -1
  54. package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.CftT9mLJ.js → stateDiagram-FHFEXIEX.COSXsD9I.js} +1 -1
  55. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.qrxrbFsX.js +1 -0
  56. package/dist/docs/assets/chunks/{theme.B_7J9ZsV.js → theme.CXJ7PNwy.js} +2 -2
  57. package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.DbU3WUNw.js → timeline-definition-GMOUNBTQ.CXdVqkLq.js} +1 -1
  58. package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.ixsq-q2u.js → vennDiagram-DHZGUBPP.CZxGuc4r.js} +1 -1
  59. package/dist/docs/assets/chunks/wardley-RL74JXVD.3oVgfqQk.js +162 -0
  60. package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.C0ewvgbp.js → wardleyDiagram-NUSXRM2D.6_irCgGJ.js} +1 -1
  61. package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.nAEhF4bO.js → xychartDiagram-5P7HB3ND.TRPe92m3.js} +1 -1
  62. package/dist/docs/assets/{evals.md.BYvfZ-PO.js → evals.md.D3Y3Aixt.js} +2 -2
  63. package/dist/docs/assets/{evals.md.BYvfZ-PO.lean.js → evals.md.D3Y3Aixt.lean.js} +1 -1
  64. package/dist/docs/assets/guides_agent-to-agent.md.CD4T5FIl.js +41 -0
  65. package/dist/docs/assets/guides_agent-to-agent.md.CD4T5FIl.lean.js +1 -0
  66. package/dist/docs/assets/guides_jev.md.F5fAkkfN.js +189 -0
  67. package/dist/docs/assets/guides_jev.md.F5fAkkfN.lean.js +1 -0
  68. package/dist/docs/assets/{reference_connections.md.CmyrlXfY.js → reference_connections.md.Je9dMsdd.js} +1 -1
  69. package/dist/docs/assets/{reference_extensions.md.Ceq-qT8d.js → reference_extensions.md.Cv5aLCz_.js} +1 -1
  70. package/dist/docs/assets/{reference_subagents.md.BHsSMMyO.js → reference_subagents.md.Dl16gcBj.js} +2 -2
  71. package/dist/docs/assets/{reference_subagents.md.BHsSMMyO.lean.js → reference_subagents.md.Dl16gcBj.lean.js} +1 -1
  72. package/dist/docs/assets/{reference_tools.md.BYzUTeVA.js → reference_tools.md.B1dH1lpa.js} +2 -2
  73. package/dist/docs/assets/{reference_tools.md.BYzUTeVA.lean.js → reference_tools.md.B1dH1lpa.lean.js} +1 -1
  74. package/dist/docs/building-with-agents.html +35 -35
  75. package/dist/docs/deployment.html +36 -36
  76. package/dist/docs/evals.html +36 -36
  77. package/dist/docs/evals.md +3 -0
  78. package/dist/docs/guides/agent-to-agent.html +65 -54
  79. package/dist/docs/guides/agent-to-agent.md +73 -68
  80. package/dist/docs/guides/bitbucket.html +35 -35
  81. package/dist/docs/guides/cloud-agents.html +35 -35
  82. package/dist/docs/guides/convert-automation.html +35 -35
  83. package/dist/docs/guides/github.html +35 -35
  84. package/dist/docs/guides/gitlab.html +35 -35
  85. package/dist/docs/guides/grokbot-agents.html +35 -35
  86. package/dist/docs/guides/improve.html +36 -36
  87. package/dist/docs/guides/jev.html +248 -0
  88. package/dist/docs/guides/jev.md +348 -0
  89. package/dist/docs/guides/mcp-oauth.html +36 -36
  90. package/dist/docs/guides/opentelemetry.html +35 -35
  91. package/dist/docs/guides/slack.html +35 -35
  92. package/dist/docs/guides/webhooks.html +35 -35
  93. package/dist/docs/hashmap.json +1 -1
  94. package/dist/docs/hillclimbing.html +35 -35
  95. package/dist/docs/index.html +35 -35
  96. package/dist/docs/llms-full.txt +434 -68
  97. package/dist/docs/llms.txt +2 -1
  98. package/dist/docs/quickstart.html +35 -35
  99. package/dist/docs/reference/agent-config.html +35 -35
  100. package/dist/docs/reference/artifacts.html +35 -35
  101. package/dist/docs/reference/channels.html +35 -35
  102. package/dist/docs/reference/cli.html +35 -35
  103. package/dist/docs/reference/connections.html +37 -37
  104. package/dist/docs/reference/connections.md +1 -1
  105. package/dist/docs/reference/evals.html +35 -35
  106. package/dist/docs/reference/extensions.html +37 -37
  107. package/dist/docs/reference/extensions.md +1 -0
  108. package/dist/docs/reference/hooks.html +35 -35
  109. package/dist/docs/reference/http-api.html +35 -35
  110. package/dist/docs/reference/instructions.html +35 -35
  111. package/dist/docs/reference/playground.html +35 -35
  112. package/dist/docs/reference/project-layout.html +35 -35
  113. package/dist/docs/reference/prompt.html +35 -35
  114. package/dist/docs/reference/schedules.html +35 -35
  115. package/dist/docs/reference/sessions.html +35 -35
  116. package/dist/docs/reference/skills.html +35 -35
  117. package/dist/docs/reference/subagents.html +37 -37
  118. package/dist/docs/reference/subagents.md +1 -1
  119. package/dist/docs/reference/tools.html +37 -37
  120. package/dist/docs/reference/tools.md +4 -0
  121. package/dist/docs/templates/agentic-owners.html +35 -35
  122. package/dist/docs/templates/pr-autofixer.html +35 -35
  123. package/dist/docs/templates/security-reviewer.html +35 -35
  124. package/dist/docs/templates/thermo-quality-review.html +35 -35
  125. package/dist/docs/templates/thermo-review.html +35 -35
  126. package/dist/docs/templates/triage.html +35 -35
  127. package/dist/docs/troubleshooting.html +35 -35
  128. package/dist/extensions/jev/extension.d.ts +43 -0
  129. package/dist/extensions/jev/extension.d.ts.map +1 -0
  130. package/dist/extensions/jev/extension.js +47 -0
  131. package/dist/extensions/jev/lib/evaluate.d.ts +101 -0
  132. package/dist/extensions/jev/lib/evaluate.d.ts.map +1 -0
  133. package/dist/extensions/jev/lib/evaluate.js +167 -0
  134. package/dist/extensions/jev/skills/gated-write.md +25 -0
  135. package/dist/extensions/jev/skills/questions.md +33 -0
  136. package/dist/extensions/jev/tools/evaluate.d.ts +4 -0
  137. package/dist/extensions/jev/tools/evaluate.d.ts.map +1 -0
  138. package/dist/extensions/jev/tools/evaluate.js +88 -0
  139. package/dist/extensions.d.ts +1 -1
  140. package/dist/extensions.d.ts.map +1 -1
  141. package/dist/extensions.js +2 -0
  142. package/dist/internal/advertise-tools.d.ts.map +1 -1
  143. package/dist/internal/advertise-tools.js +6 -0
  144. package/dist/internal/discovery/connections.d.ts.map +1 -1
  145. package/dist/internal/discovery/connections.js +18 -0
  146. package/dist/internal/discovery/extensions.d.ts.map +1 -1
  147. package/dist/internal/discovery/extensions.js +8 -4
  148. package/dist/internal/discovery/info.d.ts.map +1 -1
  149. package/dist/internal/discovery/info.js +1 -0
  150. package/dist/internal/hosted-delivery-protocol.d.ts +3 -0
  151. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  152. package/dist/internal/hosted-delivery-protocol.js +1 -0
  153. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  154. package/dist/internal/hosted-delivery.js +15 -25
  155. package/dist/internal/hosted-execution-diag.d.ts +12 -4
  156. package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
  157. package/dist/internal/hosted-execution-diag.js +26 -4
  158. package/dist/internal/hosted-execution-flush.d.ts +1 -0
  159. package/dist/internal/hosted-execution-flush.d.ts.map +1 -1
  160. package/dist/internal/hosted-execution-flush.js +4 -2
  161. package/dist/internal/server.d.ts.map +1 -1
  162. package/dist/internal/server.js +17 -9
  163. package/dist/internal/session-engine.d.ts +4 -1
  164. package/dist/internal/session-engine.d.ts.map +1 -1
  165. package/dist/internal/session-engine.js +28 -4
  166. package/dist/playground/assets/index-DSMAewbx.css +1 -0
  167. package/dist/playground/assets/{index-B1c1LeIf.js → index-De_lpFxE.js} +43 -43
  168. package/dist/playground/index.html +2 -2
  169. package/dist/types.d.ts +23 -3
  170. package/dist/types.d.ts.map +1 -1
  171. package/docs/evals.md +3 -0
  172. package/docs/guides/agent-to-agent.md +74 -69
  173. package/docs/guides/jev.md +353 -0
  174. package/docs/reference/connections.md +1 -1
  175. package/docs/reference/extensions.md +1 -0
  176. package/docs/reference/subagents.md +1 -1
  177. package/docs/reference/tools.md +4 -0
  178. package/package.json +8 -1
  179. package/src/bin/agent-serve.ts +2 -3
  180. package/src/channels/checks.ts +8 -0
  181. package/src/channels/origin/checks.ts +3 -1
  182. package/src/channels/slack/dispatch.ts +7 -2
  183. package/src/extensions/jev/extension.ts +95 -0
  184. package/src/extensions/jev/lib/evaluate.ts +289 -0
  185. package/src/extensions/jev/skills/gated-write.md +25 -0
  186. package/src/extensions/jev/skills/questions.md +33 -0
  187. package/src/extensions/jev/tools/evaluate.ts +90 -0
  188. package/src/extensions.ts +2 -0
  189. package/src/internal/advertise-tools.ts +6 -0
  190. package/src/internal/discovery/connections.ts +21 -0
  191. package/src/internal/discovery/extensions.ts +12 -4
  192. package/src/internal/discovery/info.ts +1 -0
  193. package/src/internal/hosted-delivery-protocol.ts +4 -0
  194. package/src/internal/hosted-delivery.ts +15 -0
  195. package/src/internal/hosted-execution-diag.ts +33 -4
  196. package/src/internal/hosted-execution-flush.ts +4 -0
  197. package/src/internal/server.ts +26 -12
  198. package/src/internal/session-engine.ts +30 -4
  199. package/src/types.ts +24 -3
  200. package/dist/docs/assets/chunks/@localSearchIndexroot.QmjDU6Jh.js +0 -1
  201. package/dist/docs/assets/chunks/channel.BjpoSbz_.js +0 -1
  202. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.BgxOlMHw.js +0 -1
  203. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.BgxOlMHw.js +0 -1
  204. package/dist/docs/assets/chunks/clone.DRuGBKZC.js +0 -1
  205. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.-43J68xB.js +0 -1
  206. package/dist/docs/assets/chunks/wardley-RL74JXVD.WRXz-Dux.js +0 -162
  207. package/dist/docs/assets/guides_agent-to-agent.md.8oDTfu-E.js +0 -30
  208. package/dist/docs/assets/guides_agent-to-agent.md.8oDTfu-E.lean.js +0 -1
  209. package/dist/playground/assets/index-CK2LX3iD.css +0 -1
  210. /package/dist/docs/assets/{reference_connections.md.CmyrlXfY.lean.js → reference_connections.md.Je9dMsdd.lean.js} +0 -0
  211. /package/dist/docs/assets/{reference_extensions.md.Ceq-qT8d.lean.js → reference_extensions.md.Cv5aLCz_.lean.js} +0 -0
@@ -0,0 +1,353 @@
1
+ ---
2
+ title: "Jev"
3
+ description: "Use typed Jev decisions to filter review findings, route pull requests, and gate software-factory writes."
4
+ ---
5
+
6
+ # Use Jev in review tools
7
+
8
+ Use Jev for narrow decisions where your software factory needs a typed
9
+ answer, not another paragraph. A review agent can filter speculative
10
+ findings, classify pull request risk, choose a reviewer, or decide
11
+ whether a merge needs a documentation follow-up. Jev returns a choice,
12
+ score, or probability; your TypeScript decides what happens next.
13
+
14
+ Ask one question per judgment. If an approval depends on risk, test
15
+ coverage, and the size of the change, ask three questions in one call
16
+ and combine the answers in code.
17
+
18
+ Set `TYPESAFE_API_KEY`. The default model is `jev-latest`.
19
+
20
+ ```ts
21
+ // agent/extensions/jev.ts
22
+ import jev from "@cursor/july/extensions/jev";
23
+
24
+ export default jev();
25
+ ```
26
+
27
+ ## Start only the review turns you need
28
+
29
+ You can call Jev from a channel hook before a model turn starts. When a
30
+ pull request opens, this hook reads its title, labels, and filenames,
31
+ then asks whether the change needs security review. A high probability
32
+ starts the review. Otherwise the hook returns `null`, so the agent does
33
+ not run and nothing is posted to GitHub.
34
+
35
+ ```ts
36
+ // agent/channels/github.ts
37
+ import {
38
+ defaultGitHubAuth,
39
+ githubChannel,
40
+ } from "@cursor/july/channels/github";
41
+ import { above, decide } from "@cursor/july/extensions/jev";
42
+
43
+ export default githubChannel({
44
+ botName: "security-reviewer",
45
+ cursorAccount: { repos: ["acme/checkout"] },
46
+ onPullRequest: async (ctx, pr) => {
47
+ if (pr.action !== "opened" && pr.action !== "ready_for_review") {
48
+ return null;
49
+ }
50
+
51
+ const octokit = await ctx.github.getOctokit();
52
+ const [{ data }, files] = await Promise.all([
53
+ octokit.rest.pulls.get({
54
+ owner: ctx.repository.owner,
55
+ repo: ctx.repository.name,
56
+ pull_number: pr.number,
57
+ }),
58
+ octokit.paginate(octokit.rest.pulls.listFiles, {
59
+ owner: ctx.repository.owner,
60
+ repo: ctx.repository.name,
61
+ pull_number: pr.number,
62
+ }),
63
+ ]);
64
+ const answers = await decide({
65
+ state: {
66
+ title: data.title,
67
+ body: data.body,
68
+ labels: data.labels.map(label => label.name),
69
+ files: files.map(file => file.filename),
70
+ },
71
+ questions: {
72
+ review: {
73
+ type: "boolean",
74
+ instructions:
75
+ "Does this change need security review? Answer yes for auth, permissions, secrets, request parsing, or external inputs.",
76
+ },
77
+ },
78
+ });
79
+
80
+ if (!above(answers.review, 0.8)) {
81
+ return null;
82
+ }
83
+ // `auth` starts a model turn running as the pull request sender.
84
+ return { auth: defaultGitHubAuth(ctx) };
85
+ },
86
+ });
87
+ ```
88
+
89
+ Only pull request metadata goes to Jev here. The review turn still reads
90
+ the diff itself.
91
+
92
+ ## Filter findings before you post them
93
+
94
+ Let the chat model draft a finding, then ask Jev whether the finding is
95
+ a real bug in the new code. Below your threshold, the tool returns and
96
+ the author never sees the draft. Above it, the finding becomes a review
97
+ comment.
98
+
99
+ ```ts
100
+ // agent/tools/post_finding.ts
101
+ import { parseGitHubPrContinuationKey } from "@cursor/july/channels/github";
102
+ import { above, decide } from "@cursor/july/extensions/jev";
103
+ import { defineTool } from "@cursor/july/tools";
104
+ import { z } from "zod";
105
+
106
+ export default defineTool({
107
+ description:
108
+ "Post one security finding on this session's pull request. Call once. Hold when it is not a real bug.",
109
+ inputSchema: z.object({
110
+ title: z.string(),
111
+ summary: z.string().describe("What the pull request changes."),
112
+ draft: z.string().describe("The finding to post, one or two sentences."),
113
+ }),
114
+ async execute({ title, summary, draft }, ctx) {
115
+ if (ctx.session.purpose === "eval") {
116
+ return { posted: false, reason: "eval" };
117
+ }
118
+
119
+ const ref = parseGitHubPrContinuationKey(ctx.session.continuationKey ?? "");
120
+ if (ref === undefined) {
121
+ throw new Error("post_finding requires a GitHub pull request session");
122
+ }
123
+
124
+ const answers = await decide({
125
+ state: { title, summary, draft },
126
+ questions: {
127
+ real: {
128
+ type: "boolean",
129
+ instructions:
130
+ "Is the draft an exploitable bug in the new code, not a style note or a hypothetical?",
131
+ },
132
+ },
133
+ });
134
+
135
+ if (!above(answers.real, 0.85)) {
136
+ return { posted: false, reason: "clean" };
137
+ }
138
+
139
+ const octokit = await ctx.host.github.getOctokit();
140
+ await octokit.rest.pulls.createReview({
141
+ owner: ref.owner,
142
+ repo: ref.repo,
143
+ pull_number: ref.number,
144
+ event: "COMMENT",
145
+ body: draft,
146
+ });
147
+ return {
148
+ posted: true,
149
+ pr: `${ref.owner}/${ref.repo}#${ref.number}`,
150
+ };
151
+ },
152
+ });
153
+ ```
154
+
155
+ ## Approve changes by risk tier
156
+
157
+ You can use the same pattern for Agentic Owners. Ask Jev to put the
158
+ pull request in a closed set of risk tiers. Approve only a confident
159
+ `very-low` or `low`; send everything else to a person.
160
+
161
+ ```ts
162
+ import { decide, needsHuman } from "@cursor/july/extensions/jev";
163
+
164
+ const answers = await decide({
165
+ state: { title, summary },
166
+ questions: {
167
+ risk: {
168
+ type: "choice",
169
+ instructions: "What risk tier is this pull request?",
170
+ criteria: {
171
+ "very-low": "docs, formatting, or a mechanical rename",
172
+ low: "a local change with tests and no new trust boundary",
173
+ medium: "auth, billing, or a behavior change callers depend on",
174
+ high: "a likely exploit, data loss, or a broken public contract",
175
+ },
176
+ },
177
+ },
178
+ });
179
+
180
+ const tier = answers.risk.choice;
181
+ if (needsHuman(answers.risk) || tier === "medium" || tier === "high") {
182
+ return { verdict: "hold", tier };
183
+ }
184
+ return { verdict: "approve", tier };
185
+ ```
186
+
187
+ Your GitHub tool resolves the pull request from `ctx.session` and posts
188
+ that verdict. The model does not choose the repository, pull request, or
189
+ approval event.
190
+
191
+ ## Open documentation follow-ups selectively
192
+
193
+ After a pull request merges, a code-wiki agent can ask whether the
194
+ change introduced a durable fact that belongs in the docs. A low
195
+ probability means no follow-up. A high probability opens a documentation
196
+ pull request instead of turning every merge into churn.
197
+
198
+ ```ts
199
+ import { above, decide } from "@cursor/july/extensions/jev";
200
+ import { openDocsPullRequest } from "../lib/wiki";
201
+
202
+ const answers = await decide({
203
+ state: { title, summary },
204
+ questions: {
205
+ updateDocs: {
206
+ type: "boolean",
207
+ instructions:
208
+ "Does this merge change a durable contract that the project docs should explain?",
209
+ },
210
+ },
211
+ });
212
+
213
+ if (!above(answers.updateDocs, 0.8)) {
214
+ return { action: "skip" };
215
+ }
216
+ return openDocsPullRequest({ title, summary });
217
+ ```
218
+
219
+ ## Write tools with Jev
220
+
221
+ `decide` is a regular async host function. Call it from a channel hook,
222
+ server tool, or router. It returns the answer map directly. `evaluate`
223
+ makes the same request and returns `{ answers }`.
224
+
225
+ Use a boolean for a yes-or-no gate, a choice for a closed set such as
226
+ risk tiers or owners, and a score for an ordered rubric. `above` checks
227
+ a boolean probability or score. `needsHuman` checks whether a boolean
228
+ or the selected choice clears your confidence bar.
229
+
230
+ Keep the questions atomic and combine them in TypeScript. For example,
231
+ ask separately whether a finding is real, whether its impact is
232
+ user-visible, and whether the changed line is new. Your code owns the
233
+ rule that decides whether all three are enough to post.
234
+
235
+ ## Let the agent ask Jev
236
+
237
+ Mounting the extension adds a read-only harness tool named
238
+ `<namespace>__evaluate`. With the default `jev` filename, the model sees
239
+ `jev__evaluate`.
240
+
241
+ The tool accepts one state and a list of boolean, choice, or score
242
+ questions. It returns `{ answers }` and never posts, approves, or opens
243
+ a pull request. Use it when the agent needs the result during the turn.
244
+ Use `decide` inside a project tool when the answer and the write belong
245
+ in one operation.
246
+
247
+ ## Skills included with the extension
248
+
249
+ The extension adds two skills by default:
250
+
251
+ - `jev__questions` teaches the model how to structure atomic questions,
252
+ choose a question type, and read the answers.
253
+
254
+ - `jev__gated-write` teaches the model to put `decide` and the write in
255
+ one server tool, hold on low confidence, and skip writes during evals.
256
+
257
+ The model sees each skill's description and loads the full procedure
258
+ when it applies.
259
+
260
+ ## Choose what to mount
261
+
262
+ Both contribution groups are on by default. Turn off the harness tool
263
+ when Jev should only run inside tools you wrote. Turn off the skills
264
+ when your agent already has its own Jev instructions.
265
+
266
+ ```ts
267
+ // agent/extensions/jev.ts
268
+ import jev from "@cursor/july/extensions/jev";
269
+
270
+ export default jev({
271
+ harnessTools: false,
272
+ skills: true,
273
+ });
274
+ ```
275
+
276
+ `harnessTools: false` removes `jev__evaluate` from discovery.
277
+ `skills: false` removes both Jev skills. These switches do not remove
278
+ the exported helpers, so project tools can still import `decide`,
279
+ `above`, and `needsHuman`.
280
+
281
+ ## Jev and trajectory evals
282
+
283
+ An eval checks a whole turn: the agent called the read, and it stayed
284
+ off approve. `decide` is the one call inside the tool, before GitHub.
285
+ Use the [Evals guide](../evals.md) when you want the turn to keep
286
+ behaving. Use `decide` when the tool itself needs a tier or a yes.
287
+
288
+ ## Test without the live API
289
+
290
+ Pass `fetch` and `apiKey` and the same `decide` path runs in a test.
291
+
292
+ ```ts
293
+ import { decide } from "@cursor/july/extensions/jev";
294
+
295
+ const answers = await decide({
296
+ state: {
297
+ title: "Skip the refund auth check",
298
+ summary: "acme/checkout#42 drops the session check on POST /refunds.",
299
+ },
300
+ questions: {
301
+ risk: {
302
+ type: "choice",
303
+ instructions: "What risk tier is this pull request?",
304
+ criteria: {
305
+ "very-low": "docs, formatting, or a mechanical rename",
306
+ low: "a local change with tests and no new trust boundary",
307
+ medium: "auth, billing, or a behavior change callers depend on",
308
+ high: "a likely exploit, data loss, or a broken public contract",
309
+ },
310
+ },
311
+ },
312
+ apiKey: "sk-test",
313
+ fetch: async () =>
314
+ new Response(
315
+ JSON.stringify({
316
+ answers: {
317
+ risk: {
318
+ type: "choice",
319
+ choice: "high",
320
+ probabilities: {
321
+ "very-low": 0.02,
322
+ low: 0.05,
323
+ medium: 0.18,
324
+ high: 0.75,
325
+ },
326
+ },
327
+ },
328
+ }),
329
+ { status: 200 }
330
+ ),
331
+ });
332
+ ```
333
+
334
+ ## Practices
335
+
336
+ - Pass the pull request title, a short summary, and the draft finding.
337
+ Don't send the checkout.
338
+
339
+ - Calibrate `above` and `needsHuman` on pull requests you have already
340
+ labeled. `needsHuman` defaults to `0.7`.
341
+
342
+ ## Related
343
+
344
+ - [Agentic owners](../templates/agentic-owners.md): a risk tier, then
345
+ the host approves or asks for reviewers
346
+ - [Security reviewer](../templates/security-reviewer.md): a finding, or
347
+ no comment
348
+ - [Thermo review](../templates/thermo-review.md): bugs and breakage,
349
+ posted the same way
350
+ - [Code wiki](../reference/cli.md#init): documentation
351
+ follow-ups after a merge
352
+ - [Evals](../evals.md): checks on the full turn
353
+ - [GitHub agents](./github.md): how the review gets onto the pull request
@@ -256,7 +256,7 @@ export default defineConnection({
256
256
  ```
257
257
 
258
258
  Unknown slugs and self-references fail `serve` at startup. Walkthrough:
259
- [Agent-to-agent](../guides/agent-to-agent.md#how-do-i-wire-two-agents).
259
+ [Peer agents](../guides/agent-to-agent.md#delegate-a-question-to-a-specialist).
260
260
 
261
261
  ## Every model-visible MCP connection is available in three places
262
262
 
@@ -192,6 +192,7 @@ namespace-neutral because the consumer chooses the final prefix.
192
192
  - [Cloud agents](../guides/cloud-agents.md): delegate repository work
193
193
  through an extension
194
194
  - [Grok Bot agents](../guides/grokbot-agents.md): consult named bots
195
+ - [Jev](../guides/jev.md): typed answers, then gated writes
195
196
  - [Self-improvement](../guides/improve.md): propose source changes
196
197
  through pull requests
197
198
  - [Project layout](./project-layout.md): contribution slots
@@ -54,7 +54,7 @@ subagent."
54
54
  Subagents split one job into roles inside a single agent. When the
55
55
  specialist is independently useful, with its own tools, sessions, and
56
56
  playground, make it a full agent. See
57
- [Agent-to-agent](../guides/agent-to-agent.md#peer-or-subagent).
57
+ [Peer agents](../guides/agent-to-agent.md#peer-or-subagent).
58
58
 
59
59
  ## Patterns
60
60
 
@@ -42,6 +42,10 @@ code that runs it. With a Zod `inputSchema`, the input is validated before
42
42
  `execute` runs and the input type is inferred. A plain JSON Schema
43
43
  object is forwarded as-is and the input arrives as raw JSON.
44
44
 
45
+ A server tool can call `decide` from
46
+ [`@cursor/july/extensions/jev`](../guides/jev.md) for a risk tier or a
47
+ finding gate without a second model turn.
48
+
45
49
  For multi-line descriptions, reminder prompts, and error messages, use
46
50
  [`prompt`](./prompt.md) so the string can sit indented with the surrounding
47
51
  TypeScript:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cursor/july",
3
- "version": "0.1.112",
3
+ "version": "0.1.113",
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": {
@@ -190,6 +190,13 @@
190
190
  "import": "./dist/extensions/improve/extension.js",
191
191
  "default": "./dist/extensions/improve/extension.js"
192
192
  },
193
+ "./extensions/jev": {
194
+ "anysphere-source": "./src/extensions/jev/extension.ts",
195
+ "bun": "./dist/extensions/jev/extension.js",
196
+ "types": "./dist/extensions/jev/extension.d.ts",
197
+ "import": "./dist/extensions/jev/extension.js",
198
+ "default": "./dist/extensions/jev/extension.js"
199
+ },
193
200
  "./extensions/slack-communication": {
194
201
  "anysphere-source": "./src/extensions/slack-communication/extension.ts",
195
202
  "bun": "./dist/extensions/slack-communication/extension.js",
@@ -290,9 +290,8 @@ Commands:
290
290
  cancel-runs Request cancellation for active Agent SDK v2 session runs
291
291
  and reminder clocks, and mark factory creating/active
292
292
  sessions failed. For a multi-tenant application this
293
- cancels every install, not just the caller's, and requires
294
- a team admin (service accounts cannot). Install-local
295
- cancel is stop --cancel-runs.
293
+ cancels every install, not just the caller's.
294
+ Install-local cancel is stop --cancel-runs.
296
295
  event-repos Set the repositories a multi-tenant install receives events
297
296
  for. A deploy cannot carry these; pass every repository you
298
297
  want, since the list is replaced rather than merged.
@@ -90,6 +90,14 @@ export interface CiCheckCreateInput {
90
90
  name: string;
91
91
  /** Commit the check attaches to (usually the PR head SHA). */
92
92
  sha: string;
93
+ /**
94
+ * Check suite the check files under, on forges that have one. Origin
95
+ * renders every check as `suite / check` and groups the checks tab by
96
+ * suite, so name it after the posting app (GitHub groups an app's checks
97
+ * under the app); without it the suite mirrors the check name. GitHub,
98
+ * GitLab and Bitbucket have no app-named suite and ignore it.
99
+ */
100
+ suite?: { name?: string };
93
101
  /** Initial status. Defaults to `"in_progress"`. */
94
102
  status?: "queued" | "in_progress";
95
103
  /** "Details" link on the check, e.g. the agent session run URL. */
@@ -88,8 +88,10 @@ export interface OriginCheckIdentityInput {
88
88
  externalId?: string;
89
89
  }
90
90
 
91
+ // The identity input's `suite` also carries Origin's key and details URL, so
92
+ // the forge-agnostic `suite` label is replaced rather than merged.
91
93
  export interface OriginCheckCreateInput
92
- extends OriginCheckIdentityInput, CiCheckCreateInput {}
94
+ extends OriginCheckIdentityInput, Omit<CiCheckCreateInput, "suite"> {}
93
95
 
94
96
  /**
95
97
  * Origin rejects the whole upsert when `output.title` exceeds 255 characters
@@ -434,14 +434,15 @@ export async function dispatchInboundMessage(args: {
434
434
  });
435
435
 
436
436
  const handoff = args.platformHandoff?.slackPlaceholder;
437
- const matchedHandoff =
438
- args.placeholder !== undefined &&
437
+ const handoffInThread =
439
438
  kind !== "channel_post" &&
440
439
  handoff !== undefined &&
441
440
  handoff.channelId === message.channelId &&
442
441
  handoff.threadTs === message.threadTs
443
442
  ? handoff
444
443
  : undefined;
444
+ const matchedHandoff =
445
+ args.placeholder !== undefined ? handoffInThread : undefined;
445
446
  let adoptedPlaceholder = false;
446
447
  let handoffRetracted = false;
447
448
  const retractUnadoptedHandoff = async (): Promise<void> => {
@@ -674,8 +675,12 @@ export async function dispatchInboundMessage(args: {
674
675
  });
675
676
  }
676
677
 
678
+ // A control-plane placeholder is turn scaffolding, not thread history: the
679
+ // guest posts the reply over that exact ts, so hydrating it would feed the
680
+ // model its own "still working" line as an already-sent reply.
677
681
  const excludeThreadTimestamps = [
678
682
  message.ts,
683
+ ...(handoffInThread === undefined ? [] : [handoffInThread.messageTs]),
679
684
  ...(decision.excludeThreadTimestamps ?? []),
680
685
  ];
681
686
  const mergeMessages = [triggeringMergeMessage(message)];
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Jev decisions as an extension. Mount it and the agent can ask Jev for
3
+ * typed boolean, choice, and score answers, then call `decide` from your
4
+ * own channel hooks and tools before they start a turn or write.
5
+ *
6
+ * ```ts
7
+ * // agent/extensions/jev.ts
8
+ * import jev from "@cursor/july/extensions/jev";
9
+ *
10
+ * export default jev();
11
+ * ```
12
+ *
13
+ * Contributes `<namespace>__evaluate` plus the `questions` and
14
+ * `gated-write` skills (the namespace is the mount filename). Auth is
15
+ * `TYPESAFE_API_KEY`. The default model is `jev-latest`. Custom tools
16
+ * import `decide`, `above`, and `needsHuman` from this same module. Set
17
+ * `harnessTools` or `skills` to false when the agent should not see those
18
+ * contributions.
19
+ */
20
+
21
+ import { z } from "zod";
22
+ import { defineExtension } from "../../extensions.js";
23
+ import type { Extension } from "../../types.js";
24
+ import { DEFAULT_EVALUATION_MODEL } from "./lib/evaluate.js";
25
+
26
+ /** Mount options; every field is optional. */
27
+ export interface JevOptions {
28
+ /** TypeSafe API key. Defaults to `TYPESAFE_API_KEY`. */
29
+ apiKey?: string;
30
+ /** TypeSafe model id. Defaults to `jev-latest`. */
31
+ model?: string;
32
+ /** Mount the namespaced `evaluate` harness tool. Defaults to true. */
33
+ harnessTools?: boolean;
34
+ /** Mount the `questions` and `gated-write` skills. Defaults to true. */
35
+ skills?: boolean;
36
+ }
37
+
38
+ /** {@link JevOptions} with defaults applied. */
39
+ export interface JevConfig {
40
+ apiKey?: string;
41
+ model: string;
42
+ harnessTools: boolean;
43
+ skills: boolean;
44
+ }
45
+
46
+ const config: z.ZodType<JevConfig, z.ZodTypeDef, JevOptions | undefined> = z
47
+ .object({
48
+ apiKey: z.string().min(1).optional(),
49
+ model: z.string().min(1).optional(),
50
+ harnessTools: z.boolean().default(true),
51
+ skills: z.boolean().default(true),
52
+ })
53
+ .default({})
54
+ .transform(options => ({
55
+ apiKey: options.apiKey,
56
+ model: options.model ?? DEFAULT_EVALUATION_MODEL,
57
+ harnessTools: options.harnessTools,
58
+ skills: options.skills,
59
+ }));
60
+
61
+ const jev: Extension<JevConfig, JevOptions | undefined> = defineExtension({
62
+ root: import.meta.dirname,
63
+ description: "Ask Jev for typed choice, score, and boolean answers.",
64
+ config,
65
+ contributions: options => ({
66
+ tools: options.harnessTools,
67
+ skills: options.skills,
68
+ }),
69
+ });
70
+
71
+ export type {
72
+ AnswersFor,
73
+ BooleanAnswer,
74
+ BooleanQuestion,
75
+ ChoiceAnswer,
76
+ ChoiceQuestion,
77
+ EvaluateArgs,
78
+ EvaluateResult,
79
+ EvaluationAnswer,
80
+ EvaluationQuestion,
81
+ EvaluationState,
82
+ QuestionMap,
83
+ ScoreAnswer,
84
+ ScoreQuestion,
85
+ } from "./lib/evaluate.js";
86
+ export {
87
+ above,
88
+ DEFAULT_EVALUATION_MODEL,
89
+ DEFAULT_HUMAN_THRESHOLD,
90
+ decide,
91
+ evaluate,
92
+ needsHuman,
93
+ } from "./lib/evaluate.js";
94
+
95
+ export default jev;