@cursor/july 0.1.42 → 0.1.45

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 (223) hide show
  1. package/AGENTS.md +1 -0
  2. package/dist/bin/agent-serve.js +3 -1
  3. package/dist/channels/github/api.d.ts +5 -0
  4. package/dist/channels/github/api.d.ts.map +1 -1
  5. package/dist/channels/github/api.js +18 -0
  6. package/dist/channels/github/defaults.d.ts +4 -5
  7. package/dist/channels/github/defaults.d.ts.map +1 -1
  8. package/dist/channels/github/defaults.js +27 -1
  9. package/dist/channels/github/github-channel.d.ts.map +1 -1
  10. package/dist/channels/github/github-channel.js +41 -10
  11. package/dist/channels/github/index.d.ts +1 -0
  12. package/dist/channels/github/index.d.ts.map +1 -1
  13. package/dist/channels/github/index.js +1 -0
  14. package/dist/channels/github/progress.d.ts +54 -0
  15. package/dist/channels/github/progress.d.ts.map +1 -0
  16. package/dist/channels/github/progress.js +168 -0
  17. package/dist/channels/github/state.d.ts +2 -0
  18. package/dist/channels/github/state.d.ts.map +1 -1
  19. package/dist/channels/github/state.js +1 -1
  20. package/dist/channels/github/types.d.ts +16 -4
  21. package/dist/channels/github/types.d.ts.map +1 -1
  22. package/dist/channels/slack/slack-channel.d.ts +4 -0
  23. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  24. package/dist/channels/slack/slack-channel.js +4 -0
  25. package/dist/channels.d.ts +17 -0
  26. package/dist/channels.d.ts.map +1 -1
  27. package/dist/channels.js +31 -0
  28. package/dist/docs/404.html +2 -2
  29. package/dist/docs/ab.html +4 -4
  30. package/dist/docs/assets/{app.C4-Gwi7g.js → app.fHnNXEJ6.js} +1 -1
  31. package/dist/docs/assets/chunks/@localSearchIndexroot.BMT0xM4I.js +1 -0
  32. package/dist/docs/assets/chunks/{VPLocalSearchBox.DDoLm843.js → VPLocalSearchBox.Cf6ghfFY.js} +1 -1
  33. package/dist/docs/assets/chunks/{theme.SbjGIiM0.js → theme.B_5-VLe8.js} +2 -2
  34. package/dist/docs/assets/{deployment.md.BHVjVqRa.js → deployment.md.Cdp4rTE4.js} +1 -1
  35. package/dist/docs/assets/{guides_github.md.R2QlpR75.js → guides_github.md.DSg0j9qj.js} +29 -3
  36. package/dist/docs/assets/{guides_github.md.R2QlpR75.lean.js → guides_github.md.DSg0j9qj.lean.js} +1 -1
  37. package/dist/docs/assets/guides_opentelemetry.md.Csn7ZI25.js +27 -0
  38. package/dist/docs/assets/guides_opentelemetry.md.Csn7ZI25.lean.js +1 -0
  39. package/dist/docs/assets/index.md.COeoSkcF.js +5 -0
  40. package/dist/docs/assets/index.md.COeoSkcF.lean.js +1 -0
  41. package/dist/docs/assets/{quickstart.md.rIbfahJM.js → quickstart.md.DZxBu44y.js} +18 -49
  42. package/dist/docs/assets/quickstart.md.DZxBu44y.lean.js +1 -0
  43. package/dist/docs/assets/{reference_agent-config.md.CRmkoxd6.js → reference_agent-config.md.XRpxctsA.js} +9 -4
  44. package/dist/docs/assets/{reference_agent-config.md.CRmkoxd6.lean.js → reference_agent-config.md.XRpxctsA.lean.js} +1 -1
  45. package/dist/docs/assets/{reference_channels.md.BIabFUAI.js → reference_channels.md.MN8iDy8V.js} +1 -1
  46. package/dist/docs/assets/{reference_cli.md.DqEqQpGn.js → reference_cli.md.BDmjPPAm.js} +2 -2
  47. package/dist/docs/assets/{reference_hooks.md.B40QAG6m.js → reference_hooks.md.4cbRRIIu.js} +2 -2
  48. package/dist/docs/assets/{reference_hooks.md.B40QAG6m.lean.js → reference_hooks.md.4cbRRIIu.lean.js} +1 -1
  49. package/dist/docs/assets/{reference_project-layout.md._XdeMahr.js → reference_project-layout.md.D3MdHM2z.js} +2 -1
  50. package/dist/docs/assets/{reference_tools.md.lSrsTxYJ.js → reference_tools.md.kJfJAP2m.js} +1 -1
  51. package/dist/docs/assets/templates_triage.md.CConZt1z.js +11 -0
  52. package/dist/docs/assets/templates_triage.md.CConZt1z.lean.js +1 -0
  53. package/dist/docs/building-with-agents.html +5 -5
  54. package/dist/docs/concepts.html +5 -5
  55. package/dist/docs/deployment.html +6 -6
  56. package/dist/docs/evals.html +4 -4
  57. package/dist/docs/example-agents/approval-buddy.html +4 -4
  58. package/dist/docs/example-agents/benny.html +4 -4
  59. package/dist/docs/example-agents/bugbot.html +4 -4
  60. package/dist/docs/example-agents/codebase-wiki.html +4 -4
  61. package/dist/docs/example-agents/codeowners-review.html +4 -4
  62. package/dist/docs/example-agents/concierge.html +4 -4
  63. package/dist/docs/example-agents/fsd.html +4 -4
  64. package/dist/docs/example-agents/index.html +5 -5
  65. package/dist/docs/example-agents/knowledge-base.html +4 -4
  66. package/dist/docs/example-agents/oncall.html +4 -4
  67. package/dist/docs/example-agents/security-reviewer.html +4 -4
  68. package/dist/docs/example-agents/slack-agent.html +4 -4
  69. package/dist/docs/example-agents/weather-agent.html +4 -4
  70. package/dist/docs/guides/agent-to-agent.html +4 -4
  71. package/dist/docs/guides/cloud-runtime.html +5 -5
  72. package/dist/docs/guides/github.html +33 -7
  73. package/dist/docs/guides/human-in-the-loop.html +4 -4
  74. package/dist/docs/guides/mcp-oauth.html +4 -4
  75. package/dist/docs/guides/opentelemetry.html +51 -0
  76. package/dist/docs/guides/slack.html +4 -4
  77. package/dist/docs/guides/webhooks.html +4 -4
  78. package/dist/docs/hashmap.json +1 -1
  79. package/dist/docs/hillclimbing.html +4 -4
  80. package/dist/docs/index.html +8 -27
  81. package/dist/docs/quickstart.html +24 -55
  82. package/dist/docs/reference/agent-config.html +12 -7
  83. package/dist/docs/reference/artifacts.html +4 -4
  84. package/dist/docs/reference/channels.html +6 -6
  85. package/dist/docs/reference/cli.html +7 -7
  86. package/dist/docs/reference/connections.html +4 -4
  87. package/dist/docs/reference/hooks.html +6 -6
  88. package/dist/docs/reference/http-api.html +4 -4
  89. package/dist/docs/reference/instructions.html +4 -4
  90. package/dist/docs/reference/playground.html +4 -4
  91. package/dist/docs/reference/project-layout.html +7 -6
  92. package/dist/docs/reference/prompt.html +4 -4
  93. package/dist/docs/reference/schedules.html +4 -4
  94. package/dist/docs/reference/sessions.html +4 -4
  95. package/dist/docs/reference/skills.html +4 -4
  96. package/dist/docs/reference/subagents.html +4 -4
  97. package/dist/docs/reference/tools.html +6 -6
  98. package/dist/docs/scaffolding-agents.html +4 -4
  99. package/dist/docs/storage.html +4 -4
  100. package/dist/docs/templates/triage.html +35 -0
  101. package/dist/docs/troubleshooting.html +4 -4
  102. package/dist/index.d.ts +3 -1
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +2 -1
  105. package/dist/internal/cli-ax.d.ts +1 -0
  106. package/dist/internal/cli-ax.d.ts.map +1 -1
  107. package/dist/internal/cli-ax.js +20 -5
  108. package/dist/internal/cli-deploy.d.ts.map +1 -1
  109. package/dist/internal/cli-deploy.js +38 -7
  110. package/dist/internal/deploy-client.d.ts +8 -0
  111. package/dist/internal/deploy-client.d.ts.map +1 -1
  112. package/dist/internal/deploy-client.js +5 -2
  113. package/dist/internal/discovery.d.ts.map +1 -1
  114. package/dist/internal/discovery.js +82 -13
  115. package/dist/internal/distribution.d.ts.map +1 -1
  116. package/dist/internal/distribution.js +1 -0
  117. package/dist/internal/host-otel.d.ts +25 -0
  118. package/dist/internal/host-otel.d.ts.map +1 -0
  119. package/dist/internal/host-otel.js +162 -0
  120. package/dist/internal/init-project.d.ts +24 -0
  121. package/dist/internal/init-project.d.ts.map +1 -1
  122. package/dist/internal/init-project.js +136 -17
  123. package/dist/internal/otel/attrs.d.ts +7 -0
  124. package/dist/internal/otel/attrs.d.ts.map +1 -0
  125. package/dist/internal/otel/attrs.js +13 -0
  126. package/dist/internal/otel/collector.d.ts +21 -0
  127. package/dist/internal/otel/collector.d.ts.map +1 -0
  128. package/dist/internal/otel/collector.js +605 -0
  129. package/dist/internal/otel/config.d.ts +42 -0
  130. package/dist/internal/otel/config.d.ts.map +1 -0
  131. package/dist/internal/otel/config.js +236 -0
  132. package/dist/internal/otel/http.d.ts +11 -0
  133. package/dist/internal/otel/http.d.ts.map +1 -0
  134. package/dist/internal/otel/http.js +97 -0
  135. package/dist/internal/otel/runtime.d.ts +21 -0
  136. package/dist/internal/otel/runtime.d.ts.map +1 -0
  137. package/dist/internal/otel/runtime.js +188 -0
  138. package/dist/internal/sdk-runner.d.ts +1 -1
  139. package/dist/internal/sdk-runner.d.ts.map +1 -1
  140. package/dist/internal/sdk-runner.js +1 -1
  141. package/dist/internal/server.d.ts.map +1 -1
  142. package/dist/internal/server.js +26 -1
  143. package/dist/internal/session-engine.d.ts +15 -2
  144. package/dist/internal/session-engine.d.ts.map +1 -1
  145. package/dist/internal/session-engine.js +58 -7
  146. package/dist/memory.d.ts +4 -0
  147. package/dist/memory.d.ts.map +1 -1
  148. package/dist/memory.js +4 -0
  149. package/dist/otel.d.ts +88 -0
  150. package/dist/otel.d.ts.map +1 -0
  151. package/dist/otel.js +64 -0
  152. package/dist/playground/assets/index-CZH9EFvO.css +1 -0
  153. package/dist/playground/assets/{index-B3HBneZZ.js → index-Dces8BDp.js} +34 -34
  154. package/dist/playground/index.html +2 -2
  155. package/dist/types.d.ts +103 -3
  156. package/dist/types.d.ts.map +1 -1
  157. package/docs/README.md +35 -105
  158. package/docs/deployment.md +2 -1
  159. package/docs/guides/github.md +79 -6
  160. package/docs/guides/opentelemetry.md +214 -0
  161. package/docs/quickstart.md +89 -227
  162. package/docs/reference/agent-config.md +52 -0
  163. package/docs/reference/channels.md +3 -1
  164. package/docs/reference/cli.md +2 -2
  165. package/docs/reference/hooks.md +21 -4
  166. package/docs/reference/project-layout.md +2 -0
  167. package/docs/reference/tools.md +5 -4
  168. package/docs/templates/triage.md +147 -0
  169. package/package.json +24 -2
  170. package/skills/create-agent/SKILL.md +2 -2
  171. package/skills/framework-map/SKILL.md +2 -0
  172. package/skills/otel/SKILL.md +98 -0
  173. package/src/bin/agent-serve.ts +3 -1
  174. package/src/channels/github/api.ts +22 -0
  175. package/src/channels/github/defaults.ts +27 -6
  176. package/src/channels/github/github-channel.ts +36 -1
  177. package/src/channels/github/index.ts +1 -0
  178. package/src/channels/github/progress.ts +243 -0
  179. package/src/channels/github/state.ts +3 -0
  180. package/src/channels/github/types.ts +12 -4
  181. package/src/channels/slack/slack-channel.ts +4 -0
  182. package/src/channels.ts +38 -0
  183. package/src/index.ts +7 -0
  184. package/src/internal/cli-ax.ts +21 -3
  185. package/src/internal/cli-deploy.ts +58 -3
  186. package/src/internal/deploy-client.ts +11 -0
  187. package/src/internal/discovery.ts +108 -4
  188. package/src/internal/distribution.ts +1 -0
  189. package/src/internal/host-otel.ts +252 -0
  190. package/src/internal/init-project.ts +160 -17
  191. package/src/internal/otel/attrs.ts +18 -0
  192. package/src/internal/otel/collector.ts +881 -0
  193. package/src/internal/otel/config.ts +307 -0
  194. package/src/internal/otel/http.ts +126 -0
  195. package/src/internal/otel/runtime.ts +271 -0
  196. package/src/internal/sdk-runner.ts +6 -0
  197. package/src/internal/server.ts +39 -1
  198. package/src/internal/session-engine.ts +83 -2
  199. package/src/memory.ts +4 -0
  200. package/src/otel.ts +155 -0
  201. package/src/types.ts +109 -3
  202. package/templates/triage/README.md +48 -0
  203. package/templates/triage/agent/agent.ts +14 -0
  204. package/templates/triage/agent/channels/intake.ts +20 -0
  205. package/templates/triage/agent/channels/slack.ts +3 -0
  206. package/templates/triage/agent/hooks/memory.ts +3 -0
  207. package/templates/triage/agent/instructions.md +27 -0
  208. package/templates/triage/agent/skills/triage-rubric.md +43 -0
  209. package/templates/triage/agent/tools/record_triage.ts +23 -0
  210. package/templates/triage/evals/evals.config.ts +5 -0
  211. package/templates/triage/evals/triage.eval.ts +43 -0
  212. package/templates/triage/package.json +18 -0
  213. package/templates/triage/tsconfig.json +12 -0
  214. package/dist/docs/assets/chunks/@localSearchIndexroot.BlU3A8EB.js +0 -1
  215. package/dist/docs/assets/index.md.BKpbkCa6.js +0 -24
  216. package/dist/docs/assets/index.md.BKpbkCa6.lean.js +0 -1
  217. package/dist/docs/assets/quickstart.md.rIbfahJM.lean.js +0 -1
  218. package/dist/playground/assets/index-Bqk9nplh.css +0 -1
  219. /package/dist/docs/assets/{deployment.md.BHVjVqRa.lean.js → deployment.md.Cdp4rTE4.lean.js} +0 -0
  220. /package/dist/docs/assets/{reference_channels.md.BIabFUAI.lean.js → reference_channels.md.MN8iDy8V.lean.js} +0 -0
  221. /package/dist/docs/assets/{reference_cli.md.DqEqQpGn.lean.js → reference_cli.md.BDmjPPAm.lean.js} +0 -0
  222. /package/dist/docs/assets/{reference_project-layout.md._XdeMahr.lean.js → reference_project-layout.md.D3MdHM2z.lean.js} +0 -0
  223. /package/dist/docs/assets/{reference_tools.md.lSrsTxYJ.lean.js → reference_tools.md.kJfJAP2m.lean.js} +0 -0
@@ -44,11 +44,12 @@ Choose `permissions` by what the agent needs:
44
44
  | --- | --- |
45
45
  | `"read"` | Inspect PRs / issues / statuses only |
46
46
  | `"pr-write"` (default) | Comment, review, update PR/issue metadata |
47
- | `"contents-write"` | Push code (`contents:write`) |
47
+ | `"contents-write"` | Push code, or create commit statuses |
48
48
 
49
- `contents-write` is an explicit opt-up. The host holds a push-capable
50
- token shared with model-driven tools and untrusted webhook content —
51
- prefer `"pr-write"` unless the agent must push.
49
+ `contents-write` is an explicit opt-up. Creating a commit status needs
50
+ push-equivalent access (`contents:write`); `pr-write` alone can write
51
+ comments and banners but not merge-box checks. Prefer `"pr-write"` unless
52
+ the agent must push or post commit statuses.
52
53
 
53
54
  Selected repositories must share one GitHub owner (one App installation).
54
55
  Configuration that spans owners fails at startup / mint time.
@@ -189,8 +190,8 @@ These patterns come from running a PR agent against real traffic:
189
190
  channel start. A restart must not drop buffered wakes.
190
191
  - Key sessions with a stable continuation token (`pr:owner/repo#N`) so
191
192
  every wake resumes the PR's conversation. Cross-channel resume needs
192
- an affinity store mapping PR → SDK agent id; write one from an
193
- `agent.bound` hook.
193
+ an affinity store mapping PR → SDK agent id; write it from an
194
+ `agent.bound` hook with `ctx.host.kv`.
194
195
  - Keep payload details out of wake prompts. Send a generic "re-check
195
196
  the PR" and let the agent re-read source of truth instead of trusting a
196
197
  stale snapshot.
@@ -199,9 +200,81 @@ These patterns come from running a PR agent against real traffic:
199
200
  allowlist the channel wakes for whatever deliveries reach it, and
200
201
  every wake spends real model budget.
201
202
 
203
+ ## Show PR progress
204
+
205
+ Autofix-style agents need a deterministic merge-box check and a sticky
206
+ PR comment that converges when the turn ends. Configure that on the
207
+ channel with `progress.commitStatus` and `progress.banner`. A hook can
208
+ read and write `ctx.host.kv` and `ctx.host.files` after a turn. Use
209
+ that for derived state. Keep GitHub status and banner writes on the
210
+ channel.
211
+
212
+ ```ts
213
+ import { defaultGitHubAuth, githubChannel } from "@cursor/july/channels/github";
214
+
215
+ export default githubChannel({
216
+ botName: "autofix",
217
+ deliverReplies: false,
218
+ progress: {
219
+ reactions: false,
220
+ commitStatus: {
221
+ context: "autofix",
222
+ pending: "Autofix running",
223
+ success: "Autofix finished",
224
+ failure: "Autofix failed",
225
+ },
226
+ banner: {
227
+ pending: "Autofix running…",
228
+ success: "Autofix finished",
229
+ failure: "Autofix failed",
230
+ },
231
+ },
232
+ // commitStatus needs contents-write (push-equivalent). Banner works on pr-write.
233
+ cursorAccount: {
234
+ repos: ["owner/repo"],
235
+ permissions: "contents-write",
236
+ },
237
+ onPullRequest: (ctx, pr) =>
238
+ pr.action === "opened" ? { auth: defaultGitHubAuth(ctx) } : null,
239
+ });
240
+ ```
241
+
242
+ Default stream events drive the lifecycle:
243
+
244
+ | Event | Commit status | Banner |
245
+ | --- | --- | --- |
246
+ | `turn.started` | `pending` | create (or keep) the sticky comment |
247
+ | `turn.completed` | `success` | PATCH the same comment |
248
+ | `turn.failed` / `session.failed` | `failure` | PATCH the same comment |
249
+
250
+ Omit `commitStatus` / `banner`, or set them to `false`, to keep today's
251
+ behavior. Reactions still default on; set `reactions: false` when the
252
+ eyes emoji is noise. Descriptions are optional; defaults derive from
253
+ `botName` or the status `context`.
254
+
255
+ Commit status posts to `channel.state.headSha`. PR and CI wakes seed and
256
+ refresh it (`refreshState` on continuation). A first wake that is only an
257
+ `issue_comment` has no head SHA in the payload, so status is skipped until
258
+ a PR/CI wake stores one; the banner still posts. Review-comment wakes
259
+ carry `pull_request.head.sha` when GitHub includes it.
260
+
261
+ The sticky comment id lives on durable `GitHubChannelState` (session
262
+ record). Each wake also passes `refreshState` so `headSha` / refs update
263
+ on continuation without wiping that id. Persist other derived state
264
+ with `ctx.host.kv` or `ctx.host.files`. `stateRoot` resets on hosted
265
+ replace.
266
+
267
+ Override `events` when the mapping is custom. [Approval Buddy](../example-agents/approval-buddy.md)
268
+ posts commit status from `turn.started` / `action.result` / `turn.failed`
269
+ and stays never-red; that pattern still wins when you replace a default
270
+ handler key. Handlers you author replace the matching defaults (same as
271
+ `progress.reactions` composition today).
272
+
202
273
  ## Related
203
274
 
204
275
  - [Webhooks and custom channels](./webhooks.md): the HTTP mechanism under
205
276
  this pack
206
277
  - [Evals](../evals.md): turn replay snapshots into regression fixtures
207
278
  - [Cloud runtime](./cloud-runtime.md): attach PRs to cloud VMs
279
+ - [Hooks](../reference/hooks.md): observe-only; use channel `progress` for
280
+ GitHub surfaces
@@ -0,0 +1,214 @@
1
+ ---
2
+ title: "OpenTelemetry"
3
+ description: "Push session, turn, and tool traces from the serve process to an OTLP collector you run."
4
+ ---
5
+
6
+ # OpenTelemetry
7
+
8
+ Agent SDK can push traces, metrics, and logs from the serve process to
9
+ an OTLP collector you run. Point the process at the collector with
10
+ standard `OTEL_EXPORTER_OTLP_*` env, or author `agent/otel.ts`. Traces
11
+ cover the inbound request, the session, each turn, and every tool call.
12
+
13
+ Export is opt-in. Nothing leaves the process until you set an endpoint
14
+ or a `defineOtel` config.
15
+
16
+ ## What does Agent SDK export?
17
+
18
+ | Signal | Default | What you get |
19
+ | --- | --- | --- |
20
+ | Traces | on | `agent_sdk.http` → `agent_sdk.session` → `agent_sdk.turn` → `agent_sdk.tool` / `agent_sdk.subagent` |
21
+ | Metrics | on | `cursor.token.usage`, `cursor.tool.calls`, `cursor.cost.usage`, plus `agent_sdk.*` session and turn counts |
22
+ | Logs | off | Session events as log records. Prompt text, tool payloads, and failure messages stay off unless you opt in |
23
+
24
+ Turn off a signal with `traces: false`, `metrics: false`, or `logs: false`
25
+ on `defineOtel`. Logs also turn on when you set `OTEL_LOGS_EXPORTER` to
26
+ anything other than `none`, or when you set the content flags below.
27
+
28
+ ## How do I turn OpenTelemetry export on?
29
+
30
+ Set a collector URL in the serve process environment:
31
+
32
+ ```bash
33
+ export OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com
34
+ export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer …"
35
+ ```
36
+
37
+ The default wire format is OTLP/HTTP protobuf. That matches
38
+ [Cursor enterprise OpenTelemetry Export](https://cursor.com/docs/enterprise/opentelemetry-export).
39
+ Set `OTEL_EXPORTER_OTLP_PROTOCOL=http/json` when your collector only
40
+ accepts JSON. The runtime accepts `http/protobuf` and `http/json`.
41
+ `grpc` falls back to protobuf and logs a warning.
42
+
43
+ `OTEL_EXPORTER_OTLP_ENDPOINT` is the base URL. The runtime appends
44
+ `/v1/traces`, `/v1/metrics`, and `/v1/logs`. If you pass a signal path,
45
+ it is stripped back to the base first.
46
+
47
+ To send each signal to a different collector, omit the base URL and set
48
+ the per-signal vars:
49
+
50
+ ```bash
51
+ export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://traces.example.com/v1/traces
52
+ export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://metrics.example.com/v1/metrics
53
+ export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://logs.example.com/v1/logs
54
+ ```
55
+
56
+ Optional:
57
+
58
+ | Variable | Effect |
59
+ | --- | --- |
60
+ | `OTEL_SERVICE_NAME` | Resource `service.name`. Default `cursor` |
61
+ | `OTEL_LOG_USER_PROMPTS=1` | Include user prompt text on logs and span events |
62
+ | `OTEL_LOG_TOOL_CONTENT=1` | Include tool payloads and failure text (truncated) |
63
+
64
+ `serve(dir, { otel: false })` turns export off even when env or
65
+ `agent/otel.ts` is set.
66
+
67
+ ## How do I author `agent/otel.ts`?
68
+
69
+ Use `defineOtel` when you want the collector URL, headers, or sampling
70
+ in the project instead of the environment:
71
+
72
+ ```ts
73
+ import { defineOtel } from "@cursor/july/otel";
74
+
75
+ export default defineOtel({
76
+ serviceName: "cursor",
77
+ exporters: [
78
+ {
79
+ url: "https://otel.example.com",
80
+ protocol: "http/protobuf",
81
+ headers: { Authorization: "Bearer …" },
82
+ },
83
+ ],
84
+ });
85
+ ```
86
+
87
+ Multiple `exporters` fan out to every destination. Restrict one
88
+ destination with `signals: ["traces"]`.
89
+
90
+ You can also pass the same object to `serve(dir, { otel })`. Precedence
91
+ is `serve({ otel })` over `agent/otel.ts` over env. An empty
92
+ `defineOtel()` still enables export when `OTEL_EXPORTER_OTLP_*` is set.
93
+
94
+ The companion skill is [`skills/otel/SKILL.md`](../../skills/otel/SKILL.md).
95
+
96
+ ## What spans does a session produce?
97
+
98
+ ```text
99
+ agent_sdk.http inbound channel request (W3C traceparent)
100
+ └─ agent_sdk.session cursor.conversation.id = session id
101
+ └─ agent_sdk.turn
102
+ ├─ agent_sdk.tool
103
+ └─ agent_sdk.subagent
104
+ └─ agent_sdk.tool
105
+ ```
106
+
107
+ Inbound HTTP extracts W3C `traceparent`, so a channel request parents
108
+ the session span when the turn starts in that request. Turns that
109
+ resume after restore, or a direct `callTool` with no `turn.started` in
110
+ this process, open a synthetic turn span so tool calls still nest.
111
+
112
+ ## Which attributes land on the wire?
113
+
114
+ Every signal carries these resource attributes:
115
+
116
+ - `service.name` (`cursor` unless you override it)
117
+ - `cursor.entrypoint=sdk_ts`
118
+ - `cursor.surface=unspecified`
119
+ - `agent_sdk.framework=@cursor/july`
120
+
121
+ Shared names (same keys as enterprise export):
122
+
123
+ - `cursor.conversation.id`: the session id
124
+ - `cursor.model.name`
125
+ - `cursor.token.usage` with `cursor.token.type` of `input`, `output`,
126
+ `cache_read`, `cache_creation`, or `reasoning`
127
+ - `cursor.tool.calls` with `cursor.tool.name`, `cursor.tool.kind`, and
128
+ `cursor.tool.status`
129
+ - `cursor.cost.usage` (USD)
130
+
131
+ Agent SDK only (`agent_sdk.*`): agent name, turn id, channel, call id,
132
+ subagent name, session mode, and HTTP duration (`agent_sdk.http.duration`).
133
+
134
+ ## How do I emit my own metrics?
135
+
136
+ `ctx.host.otel` is always present on tools, hooks, and channel
137
+ handlers. Counters and histograms no-op when no meter is running.
138
+ `setAttributes` still tags the open session when a collector is
139
+ attached.
140
+
141
+ Prefix metric names with your team or agent. First-party names
142
+ (`cursor.token.usage`, `cursor.tool.calls`, `cursor.cost.usage`,
143
+ `agent_sdk.session.count`, `agent_sdk.turn.count`,
144
+ `agent_sdk.subagent.count`, `agent_sdk.http.duration`) and join keys
145
+ (`cursor.conversation.id`, `agent_sdk.agent`, `agent_sdk.turn_id`,
146
+ `agent_sdk.framework`) are reserved. Custom spans are not on this
147
+ surface.
148
+
149
+ ```ts
150
+ ctx.host.otel.setAttributes({
151
+ "abc.ticket_id": "INC-123",
152
+ "abc.queue": "p1",
153
+ });
154
+ ctx.host.otel.increment("abc.ticket.resolved");
155
+ ctx.host.otel.record("abc.approval.duration_ms", 1420, {
156
+ outcome: "approved",
157
+ });
158
+ ```
159
+
160
+ A session-bound host (tools and hooks) adds `cursor.conversation.id`
161
+ and `agent_sdk.agent` for you. Tags merge: later `setAttributes` calls
162
+ paint open spans and later first-party metrics.
163
+
164
+ ## What stays off the OpenTelemetry wire?
165
+
166
+ User prompts, tool arguments, tool results, and failure messages are
167
+ omitted by default. Failure spans still record an error status with a
168
+ generic message (`turn failed` / `session failed`).
169
+
170
+ Opt in with `OTEL_LOG_USER_PROMPTS=1` and `OTEL_LOG_TOOL_CONTENT=1`, or
171
+ the matching `logs: { userPrompts, toolContent }` fields on
172
+ `defineOtel`. Opted-in strings truncate at 2,048 characters.
173
+
174
+ Deployment URLs from `agent.bound` stay off spans unless
175
+ `toolContent` is on.
176
+
177
+ ## How does Agent SDK export relate to Cursor enterprise export?
178
+
179
+ [Cursor enterprise OpenTelemetry Export](https://cursor.com/docs/enterprise/opentelemetry-export)
180
+ is the team-admin path. Cursor servers send org-wide metrics and logs
181
+ to a collector you configure in Team Settings.
182
+
183
+ Agent SDK export is the process-local path. The serve process sends
184
+ per-run traces, and optional metrics and logs, to a collector you
185
+ point it at.
186
+
187
+ Point both at the same collector when you want one view. Group on
188
+ `cursor.conversation.id`. Resource defaults (`service.name=cursor`,
189
+ `cursor.entrypoint=sdk_ts`) keep the streams next to each other. The
190
+ [wire reference](https://cursor.com/docs/enterprise/opentelemetry-export/wire)
191
+ lists the shared attribute names.
192
+
193
+ Evals (`defineEval`) stay the in-product regression check. OpenTelemetry
194
+ is the graph in your observability stack.
195
+
196
+ ## What if another OpenTelemetry SDK is already running?
197
+
198
+ OTel providers are process-global. If Cursor CLI, an extension host, or
199
+ another library already registered a TracerProvider, MeterProvider, or
200
+ LoggerProvider, Agent SDK reuses it. Run `serve` as its own process
201
+ when the Agent SDK exporters should own the destination.
202
+
203
+ Two mounts with different `agent/otel.ts` files fail at serve start.
204
+ Use the same `defineOtel` config on every mount, or configure once
205
+ through `serve({ otel })` or env.
206
+
207
+ ## What's next
208
+
209
+ - [`skills/otel/SKILL.md`](../../skills/otel/SKILL.md): compact
210
+ `defineOtel` reference for coding agents
211
+ - [Hooks](../reference/hooks.md): observe the same session event stream
212
+ in-process
213
+ - [Deployment](../deployment.md): env, secrets, and self-hosting
214
+ - [Cursor enterprise OpenTelemetry Export](https://cursor.com/docs/enterprise/opentelemetry-export)