@cursor/july 0.1.30 → 0.1.32
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.
- package/AGENTS.md +1 -1
- package/README.md +10 -5
- package/dist/bin/agent-serve.js +4 -4
- package/dist/channels/github/index.d.ts +1 -1
- package/dist/channels/github/index.js +1 -1
- package/dist/channels/slack/bot-mentions.d.ts +1 -1
- package/dist/channels/slack/bot-mentions.d.ts.map +1 -1
- package/dist/channels/slack/bot-mentions.js +1 -1
- package/dist/channels/slack/eval-directive.js +1 -1
- package/dist/channels/slack/external-policy.d.ts +1 -1
- package/dist/channels/slack/external-policy.js +1 -1
- package/dist/channels/slack/log.d.ts +1 -1
- package/dist/channels/slack/log.js +1 -1
- package/dist/channels/slack/post-update-delivery.d.ts +85 -0
- package/dist/channels/slack/post-update-delivery.d.ts.map +1 -0
- package/dist/channels/slack/setup.js +1 -1
- package/dist/channels/slack/socket-mode.js +1 -1
- package/dist/docs/404.html +3 -3
- package/dist/docs/ab.html +11 -11
- package/dist/docs/assets/{ab.md.BMCZ6Hd7.js → ab.md.DAQoJ-up.js} +6 -6
- package/dist/docs/assets/{ab.md.BMCZ6Hd7.lean.js → ab.md.DAQoJ-up.lean.js} +1 -1
- package/dist/docs/assets/{app.Cm4lsMc4.js → app.C2aVczmo.js} +1 -1
- package/dist/docs/assets/building-with-agents.md.CnHqvYDd.js +13 -0
- package/dist/docs/assets/{building-with-agents.md.CJCtZCyi.lean.js → building-with-agents.md.CnHqvYDd.lean.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.xgMnlUSO.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.CYUFXspH.js → VPLocalSearchBox.DLEzetbD.js} +1 -1
- package/dist/docs/assets/chunks/{theme.CTjkX9vc.js → theme.BkOH1oMp.js} +2 -2
- package/dist/docs/assets/concepts.md.DFaQEFkA.js +4 -0
- package/dist/docs/assets/concepts.md.DFaQEFkA.lean.js +1 -0
- package/dist/docs/assets/deployment.md.9MYBuKM1.js +55 -0
- package/dist/docs/assets/deployment.md.9MYBuKM1.lean.js +1 -0
- package/dist/docs/assets/{evals.md.DYOjkRCX.js → evals.md.BIUoVZ6X.js} +13 -13
- package/dist/docs/assets/evals.md.BIUoVZ6X.lean.js +1 -0
- package/dist/docs/assets/{example-agents_approval-buddy.md.DFGBYLcc.js → example-agents_approval-buddy.md.BhEfleVx.js} +4 -4
- package/dist/docs/assets/{example-agents_approval-buddy.md.DFGBYLcc.lean.js → example-agents_approval-buddy.md.BhEfleVx.lean.js} +1 -1
- package/dist/docs/assets/example-agents_benny.md.2Et1qa8f.js +7 -0
- package/dist/docs/assets/{example-agents_bugbot.md.DelIdhxB.js → example-agents_bugbot.md.ByUexi5i.js} +5 -5
- package/dist/docs/assets/{example-agents_codebase-wiki.md.DC6sgwn0.js → example-agents_codebase-wiki.md.B4y-7ZVW.js} +6 -6
- package/dist/docs/assets/{example-agents_codebase-wiki.md.DC6sgwn0.lean.js → example-agents_codebase-wiki.md.B4y-7ZVW.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_codeowners-review.md.Ku_tG2RY.js → example-agents_codeowners-review.md.D6ay4nvf.js} +6 -6
- package/dist/docs/assets/{example-agents_codeowners-review.md.Ku_tG2RY.lean.js → example-agents_codeowners-review.md.D6ay4nvf.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_concierge.md.4rQTSMXt.js → example-agents_concierge.md.lL8rhYlj.js} +7 -7
- package/dist/docs/assets/{example-agents_fsd.md.CzgUrDfi.js → example-agents_fsd.md.DfNKQTHz.js} +5 -5
- package/dist/docs/assets/example-agents_index.md.DgGBwckv.js +2 -0
- package/dist/docs/assets/example-agents_index.md.DgGBwckv.lean.js +1 -0
- package/dist/docs/assets/{example-agents_knowledge-base.md.BPJiVueF.js → example-agents_knowledge-base.md.CzyZ2DCr.js} +5 -5
- package/dist/docs/assets/{example-agents_knowledge-base.md.BPJiVueF.lean.js → example-agents_knowledge-base.md.CzyZ2DCr.lean.js} +1 -1
- package/dist/docs/assets/example-agents_oncall.md.wFFXXEyW.js +10 -0
- package/dist/docs/assets/{example-agents_security-reviewer.md.Dhj_m7_B.js → example-agents_security-reviewer.md.Dkf1gyo6.js} +8 -8
- package/dist/docs/assets/example-agents_slack-agent.md.DvgvT4nn.js +5 -0
- package/dist/docs/assets/example-agents_weather-agent.md.Dmrcphhl.js +24 -0
- package/dist/docs/assets/example-agents_weather-agent.md.Dmrcphhl.lean.js +1 -0
- package/dist/docs/assets/{guides_agent-to-agent.md.Bpzgq2Pq.js → guides_agent-to-agent.md.Bmbxy-FA.js} +4 -4
- package/dist/docs/assets/guides_cloud-runtime.md.BZ2GA7Es.js +9 -0
- package/dist/docs/assets/{guides_github.md.DOOCpqsW.js → guides_github.md.R2QlpR75.js} +5 -5
- package/dist/docs/assets/{guides_human-in-the-loop.md.DlUqsp1S.js → guides_human-in-the-loop.md.BWvT7UqY.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.Dd8EgSem.js → guides_mcp-oauth.md.C7G7IykG.js} +5 -5
- package/dist/docs/assets/guides_mcp-oauth.md.C7G7IykG.lean.js +1 -0
- package/dist/docs/assets/guides_slack.md.zriQpU_9.js +47 -0
- package/dist/docs/assets/guides_slack.md.zriQpU_9.lean.js +1 -0
- package/dist/docs/assets/{guides_webhooks.md.wSOYas3X.js → guides_webhooks.md.DiAwSR42.js} +1 -1
- package/dist/docs/assets/{hillclimbing.md.DHNast08.js → hillclimbing.md.D9Y1_bYh.js} +1 -1
- package/dist/docs/assets/index.md.CZqbBJPB.js +20 -0
- package/dist/docs/assets/index.md.CZqbBJPB.lean.js +1 -0
- package/dist/docs/assets/{quickstart.md.BU6Iwi_9.js → quickstart.md.TnEXYgYW.js} +12 -12
- package/dist/docs/assets/{reference_agent-config.md.DrW2JUM8.js → reference_agent-config.md.kuN6-OxK.js} +1 -1
- package/dist/docs/assets/reference_cli.md.sD-IUWjg.js +73 -0
- package/dist/docs/assets/{reference_cli.md.ccoKOoXt.lean.js → reference_cli.md.sD-IUWjg.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.B9Q3TOve.js → reference_connections.md.DGqAsFXb.js} +3 -3
- package/dist/docs/assets/reference_http-api.md.CfVM_ICa.js +11 -0
- package/dist/docs/assets/{reference_project-layout.md.Bd_CKtNS.js → reference_project-layout.md.D8E6ZmHJ.js} +4 -4
- package/dist/docs/assets/{reference_project-layout.md.Bd_CKtNS.lean.js → reference_project-layout.md.D8E6ZmHJ.lean.js} +1 -1
- package/dist/docs/assets/{reference_schedules.md.w_F2mXB6.js → reference_schedules.md.gmfYzf_I.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.DLd6mvbv.js → reference_sessions.md.C_ouF_uf.js} +3 -3
- package/dist/docs/assets/{reference_tools.md.BRSDnTbN.js → reference_tools.md.BswAQM41.js} +3 -3
- package/dist/docs/assets/{scaffolding-agents.md.C3pTrmoE.js → scaffolding-agents.md.Bsr9Pwzu.js} +1 -1
- package/dist/docs/assets/{scaffolding-agents.md.C3pTrmoE.lean.js → scaffolding-agents.md.Bsr9Pwzu.lean.js} +1 -1
- package/dist/docs/assets/{storage.md.DRTdnFvd.js → storage.md.xZoiGM58.js} +3 -3
- package/dist/docs/assets/storage.md.xZoiGM58.lean.js +1 -0
- package/dist/docs/assets/troubleshooting.md.B5RVX_tL.js +1 -0
- package/dist/docs/assets/{troubleshooting.md.CmQkmnzC.lean.js → troubleshooting.md.B5RVX_tL.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +12 -12
- package/dist/docs/concepts.html +6 -6
- package/dist/docs/deployment.html +32 -32
- package/dist/docs/evals.html +19 -19
- package/dist/docs/example-agents/approval-buddy.html +9 -9
- package/dist/docs/example-agents/benny.html +11 -11
- package/dist/docs/example-agents/bugbot.html +10 -10
- package/dist/docs/example-agents/codebase-wiki.html +11 -11
- package/dist/docs/example-agents/codeowners-review.html +11 -11
- package/dist/docs/example-agents/concierge.html +12 -12
- package/dist/docs/example-agents/fsd.html +10 -10
- package/dist/docs/example-agents/index.html +7 -7
- package/dist/docs/example-agents/knowledge-base.html +10 -10
- package/dist/docs/example-agents/oncall.html +10 -10
- package/dist/docs/example-agents/security-reviewer.html +13 -13
- package/dist/docs/example-agents/slack-agent.html +10 -10
- package/dist/docs/example-agents/weather-agent.html +16 -16
- package/dist/docs/guides/agent-to-agent.html +9 -9
- package/dist/docs/guides/cloud-runtime.html +7 -7
- package/dist/docs/guides/github.html +10 -10
- package/dist/docs/guides/human-in-the-loop.html +7 -7
- package/dist/docs/guides/mcp-oauth.html +11 -11
- package/dist/docs/guides/slack.html +22 -17
- package/dist/docs/guides/webhooks.html +7 -7
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +7 -7
- package/dist/docs/index.html +9 -9
- package/dist/docs/quickstart.html +17 -17
- package/dist/docs/reference/agent-config.html +7 -7
- package/dist/docs/reference/channels.html +5 -5
- package/dist/docs/reference/cli.html +56 -48
- package/dist/docs/reference/connections.html +9 -9
- package/dist/docs/reference/hooks.html +5 -5
- package/dist/docs/reference/http-api.html +7 -7
- package/dist/docs/reference/instructions.html +5 -5
- package/dist/docs/reference/playground.html +5 -5
- package/dist/docs/reference/project-layout.html +9 -9
- package/dist/docs/reference/prompt.html +5 -5
- package/dist/docs/reference/schedules.html +7 -7
- package/dist/docs/reference/sessions.html +8 -8
- package/dist/docs/reference/skills.html +5 -5
- package/dist/docs/reference/subagents.html +5 -5
- package/dist/docs/reference/tools.html +9 -9
- package/dist/docs/scaffolding-agents.html +6 -6
- package/dist/docs/storage.html +9 -9
- package/dist/docs/troubleshooting.html +6 -6
- package/dist/evals/reporters.d.ts +1 -1
- package/dist/evals/reporters.js +1 -1
- package/dist/evals.d.ts +2 -2
- package/dist/files-backends/agent-store-presigned-url.d.ts +3 -0
- package/dist/files-backends/agent-store-presigned-url.d.ts.map +1 -0
- package/dist/files-backends/agent-store-presigned-url.js +1023 -0
- package/dist/files-backends/cursor-hosted.d.ts +87 -0
- package/dist/files-backends/cursor-hosted.d.ts.map +1 -0
- package/dist/files-backends/cursor-hosted.js +563 -0
- package/dist/files-backends/local-fs.d.ts +33 -0
- package/dist/files-backends/local-fs.d.ts.map +1 -0
- package/dist/files-backends/local-fs.js +199 -0
- package/dist/files.d.ts +139 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +89 -0
- package/dist/internal/ab-collector.js +2 -2
- package/dist/internal/ab-fold.js +1 -1
- package/dist/internal/cli-ax.d.ts +2 -2
- package/dist/internal/cli-ax.js +2 -2
- package/dist/internal/cli-deploy.d.ts +1 -1
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +7 -2
- package/dist/internal/cli-docs.d.ts +1 -1
- package/dist/internal/cli-docs.js +1 -1
- package/dist/internal/cli-github.js +13 -13
- package/dist/internal/cli-mcp-oauth.d.ts +1 -1
- package/dist/internal/cli-mcp-oauth.js +2 -2
- package/dist/internal/cli-mcp.d.ts +3 -3
- package/dist/internal/cli-mcp.js +4 -4
- package/dist/internal/cli-skills.js +1 -1
- package/dist/internal/cloud-turn-cost.d.ts +9 -1
- package/dist/internal/cloud-turn-cost.d.ts.map +1 -1
- package/dist/internal/cloud-turn-cost.js +14 -4
- package/dist/internal/cursor/account-mcp.js +5 -5
- package/dist/internal/cursor/backend-client.js +1 -1
- package/dist/internal/cursor/github-credentials.js +3 -3
- package/dist/internal/cursor-account-mcp-auth.d.ts +1 -1
- package/dist/internal/cursor-account-mcp-auth.js +1 -1
- package/dist/internal/cursor-event-relay.js +1 -1
- package/dist/internal/cursor-relay-core.d.ts +1 -1
- package/dist/internal/cursor-relay-core.d.ts.map +1 -1
- package/dist/internal/cursor-slack-relay.js +1 -1
- package/dist/internal/deploy-client.d.ts +6 -1
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +3 -2
- package/dist/internal/deploy-source.d.ts +2 -2
- package/dist/internal/deploy-source.js +2 -2
- package/dist/internal/discovery.js +2 -2
- package/dist/internal/distribution.d.ts +5 -5
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +6 -6
- package/dist/internal/docs-site.js +5 -5
- package/dist/internal/eval-run-store.js +8 -8
- package/dist/internal/evals-client.d.ts +1 -1
- package/dist/internal/evals-client.js +1 -1
- package/dist/internal/github-fanout.js +2 -2
- package/dist/internal/host-files.d.ts +29 -0
- package/dist/internal/host-files.d.ts.map +1 -0
- package/dist/internal/host-files.js +283 -0
- package/dist/internal/host-platforms.js +5 -5
- package/dist/internal/hosting.d.ts +1 -1
- package/dist/internal/hosting.js +1 -1
- package/dist/internal/http-channel.d.ts.map +1 -1
- package/dist/internal/http-channel.js +26 -0
- package/dist/internal/install-cursor-skills.d.ts +1 -1
- package/dist/internal/install-cursor-skills.d.ts.map +1 -1
- package/dist/internal/install-cursor-skills.js +33 -4
- package/dist/internal/json-dir-store.d.ts +32 -0
- package/dist/internal/json-dir-store.d.ts.map +1 -0
- package/dist/internal/local-control-plane.js +2 -2
- package/dist/internal/logs-client.d.ts +2 -2
- package/dist/internal/logs-client.js +2 -2
- package/dist/internal/mcp-endpoint.js +1 -1
- package/dist/internal/mcp-oauth.js +2 -2
- package/dist/internal/persistence-coordinator.d.ts +127 -0
- package/dist/internal/persistence-coordinator.d.ts.map +1 -0
- package/dist/internal/platform-schedule-sync.js +2 -2
- package/dist/internal/playground/toolchain.js +6 -6
- package/dist/internal/reminder-runner.js +13 -13
- package/dist/internal/resolved-connections.js +6 -6
- package/dist/internal/schedule-runner.js +1 -1
- package/dist/internal/sdk-runner.js +5 -5
- package/dist/internal/server.js +16 -16
- package/dist/internal/session-cost.d.ts +3 -2
- package/dist/internal/session-cost.d.ts.map +1 -1
- package/dist/internal/session-cost.js +7 -6
- package/dist/internal/session-engine.d.ts +31 -1
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +119 -31
- package/dist/internal/slack-provision-client.js +1 -1
- package/dist/internal/storage-coordinator.js +7 -7
- package/dist/internal/trajectory.js +2 -2
- package/dist/internal/turn-cost.d.ts +27 -0
- package/dist/internal/turn-cost.d.ts.map +1 -0
- package/dist/internal/turn-cost.js +83 -0
- package/dist/internal/update-check.d.ts +3 -3
- package/dist/internal/update-check.d.ts.map +1 -1
- package/dist/internal/update-check.js +5 -5
- package/dist/memory.d.ts +1 -1
- package/dist/memory.js +1 -1
- package/dist/multi-tenant.d.ts +80 -0
- package/dist/multi-tenant.d.ts.map +1 -0
- package/dist/multi-tenant.js +69 -0
- package/dist/persistence.d.ts +184 -0
- package/dist/persistence.d.ts.map +1 -0
- package/dist/playground/assets/index-50PKeJlG.css +1 -0
- package/dist/playground/assets/index-C0f2Wl1q.js +85 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +1 -1
- package/dist/types.d.ts +120 -16
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +23 -23
- package/docs/ab.md +12 -12
- package/docs/building-with-agents.md +9 -9
- package/docs/concepts.md +11 -11
- package/docs/deployment.md +55 -43
- package/docs/evals.md +20 -20
- package/docs/example-agents/approval-buddy.md +9 -9
- package/docs/example-agents/benny.md +13 -13
- package/docs/example-agents/bugbot.md +6 -6
- package/docs/example-agents/codebase-wiki.md +8 -8
- package/docs/example-agents/codeowners-review.md +8 -8
- package/docs/example-agents/concierge.md +10 -10
- package/docs/example-agents/fsd.md +7 -7
- package/docs/example-agents/index.md +8 -8
- package/docs/example-agents/knowledge-base.md +9 -9
- package/docs/example-agents/oncall.md +7 -7
- package/docs/example-agents/security-reviewer.md +12 -12
- package/docs/example-agents/slack-agent.md +10 -10
- package/docs/example-agents/weather-agent.md +30 -26
- package/docs/guides/agent-to-agent.md +4 -4
- package/docs/guides/cloud-runtime.md +3 -3
- package/docs/guides/github.md +6 -6
- package/docs/guides/human-in-the-loop.md +1 -1
- package/docs/guides/mcp-oauth.md +9 -9
- package/docs/guides/slack.md +94 -21
- package/docs/guides/webhooks.md +1 -1
- package/docs/hillclimbing.md +3 -3
- package/docs/quickstart.md +18 -18
- package/docs/reference/agent-config.md +1 -1
- package/docs/reference/cli.md +110 -79
- package/docs/reference/connections.md +3 -3
- package/docs/reference/http-api.md +2 -2
- package/docs/reference/project-layout.md +7 -7
- package/docs/reference/schedules.md +1 -1
- package/docs/reference/sessions.md +7 -7
- package/docs/reference/tools.md +3 -3
- package/docs/scaffolding-agents.md +2 -2
- package/docs/storage.md +5 -5
- package/docs/troubleshooting.md +11 -10
- package/package.json +5 -2
- package/skills/ab/SKILL.md +5 -5
- package/skills/create-agent/SKILL.md +17 -17
- package/skills/debug/SKILL.md +10 -10
- package/skills/evals/SKILL.md +13 -13
- package/skills/framework-map/SKILL.md +3 -3
- package/skills/github/SKILL.md +11 -11
- package/skills/hillclimb/SKILL.md +9 -9
- package/skills/mcp-auth/SKILL.md +11 -11
- package/skills/setup-slack/SKILL.md +28 -28
- package/src/bin/agent-serve.ts +4 -4
- package/src/channels/github/index.ts +1 -1
- package/src/channels/slack/bot-mentions.ts +1 -1
- package/src/channels/slack/eval-directive.ts +1 -1
- package/src/channels/slack/external-policy.ts +1 -1
- package/src/channels/slack/log.ts +1 -1
- package/src/channels/slack/setup.ts +1 -1
- package/src/channels/slack/socket-mode.ts +1 -1
- package/src/evals/reporters.ts +1 -1
- package/src/evals.ts +2 -2
- package/src/files-backends/agent-store-presigned-url.ts +8 -0
- package/src/files-backends/cursor-hosted.ts +724 -0
- package/src/files-backends/local-fs.ts +178 -0
- package/src/files.ts +195 -0
- package/src/internal/ab-collector.ts +2 -2
- package/src/internal/ab-fold.ts +1 -1
- package/src/internal/cli-ax.ts +2 -2
- package/src/internal/cli-deploy.ts +7 -2
- package/src/internal/cli-docs.ts +1 -1
- package/src/internal/cli-github.ts +13 -13
- package/src/internal/cli-mcp-oauth.ts +2 -2
- package/src/internal/cli-mcp.ts +4 -4
- package/src/internal/cli-skills.ts +1 -1
- package/src/internal/cloud-turn-cost.ts +20 -4
- package/src/internal/cursor/account-mcp.ts +5 -5
- package/src/internal/cursor/backend-client.ts +1 -1
- package/src/internal/cursor/github-credentials.ts +3 -3
- package/src/internal/cursor-account-mcp-auth.ts +1 -1
- package/src/internal/cursor-event-relay.ts +1 -1
- package/src/internal/cursor-relay-core.ts +1 -1
- package/src/internal/cursor-slack-relay.ts +1 -1
- package/src/internal/deploy-client.ts +8 -2
- package/src/internal/deploy-source.ts +2 -2
- package/src/internal/discovery.ts +2 -2
- package/src/internal/distribution.ts +6 -6
- package/src/internal/docs-site.ts +5 -5
- package/src/internal/eval-run-store.ts +8 -8
- package/src/internal/evals-client.ts +1 -1
- package/src/internal/github-fanout.ts +2 -2
- package/src/internal/host-files.ts +372 -0
- package/src/internal/host-platforms.ts +5 -5
- package/src/internal/hosting.ts +1 -1
- package/src/internal/http-channel.ts +30 -0
- package/src/internal/install-cursor-skills.ts +31 -3
- package/src/internal/local-control-plane.ts +2 -2
- package/src/internal/logs-client.ts +2 -2
- package/src/internal/mcp-endpoint.ts +1 -1
- package/src/internal/mcp-oauth.ts +2 -2
- package/src/internal/platform-schedule-sync.ts +2 -2
- package/src/internal/playground/toolchain.ts +6 -6
- package/src/internal/reminder-runner.ts +13 -13
- package/src/internal/resolved-connections.ts +6 -6
- package/src/internal/schedule-runner.ts +1 -1
- package/src/internal/sdk-runner.ts +5 -5
- package/src/internal/server.ts +16 -16
- package/src/internal/session-cost.ts +7 -6
- package/src/internal/session-engine.ts +141 -28
- package/src/internal/slack-provision-client.ts +1 -1
- package/src/internal/storage-coordinator.ts +7 -7
- package/src/internal/trajectory.ts +2 -2
- package/src/internal/turn-cost.ts +110 -0
- package/src/internal/update-check.ts +6 -6
- package/src/memory.ts +1 -1
- package/src/storage.ts +1 -1
- package/src/types.ts +148 -16
- package/dist/docs/assets/building-with-agents.md.CJCtZCyi.js +0 -13
- package/dist/docs/assets/chunks/@localSearchIndexroot.CbQshWFK.js +0 -1
- package/dist/docs/assets/concepts.md.Cfb9b-k1.js +0 -4
- package/dist/docs/assets/concepts.md.Cfb9b-k1.lean.js +0 -1
- package/dist/docs/assets/deployment.md.TecHo0_2.js +0 -55
- package/dist/docs/assets/deployment.md.TecHo0_2.lean.js +0 -1
- package/dist/docs/assets/evals.md.DYOjkRCX.lean.js +0 -1
- package/dist/docs/assets/example-agents_benny.md.B0gjhI-p.js +0 -7
- package/dist/docs/assets/example-agents_index.md.D2PEVSXl.js +0 -2
- package/dist/docs/assets/example-agents_index.md.D2PEVSXl.lean.js +0 -1
- package/dist/docs/assets/example-agents_oncall.md.BG_sUMly.js +0 -10
- package/dist/docs/assets/example-agents_slack-agent.md.buLbgvBf.js +0 -5
- package/dist/docs/assets/example-agents_weather-agent.md.C9Qv-W0o.js +0 -24
- package/dist/docs/assets/example-agents_weather-agent.md.C9Qv-W0o.lean.js +0 -1
- package/dist/docs/assets/guides_cloud-runtime.md.gVzabdQL.js +0 -9
- package/dist/docs/assets/guides_mcp-oauth.md.Dd8EgSem.lean.js +0 -1
- package/dist/docs/assets/guides_slack.md.CjmJSvZS.js +0 -42
- package/dist/docs/assets/guides_slack.md.CjmJSvZS.lean.js +0 -1
- package/dist/docs/assets/index.md.CH_s5uZe.js +0 -20
- package/dist/docs/assets/index.md.CH_s5uZe.lean.js +0 -1
- package/dist/docs/assets/reference_cli.md.ccoKOoXt.js +0 -65
- package/dist/docs/assets/reference_http-api.md.BncLd3PZ.js +0 -11
- package/dist/docs/assets/storage.md.DRTdnFvd.lean.js +0 -1
- package/dist/docs/assets/troubleshooting.md.CmQkmnzC.js +0 -1
- package/dist/internal/model-pricing.d.ts +0 -49
- package/dist/internal/model-pricing.d.ts.map +0 -1
- package/dist/internal/model-pricing.js +0 -377
- package/dist/playground/assets/index-CquRB-l0.js +0 -85
- package/dist/playground/assets/index-Dj0bWpkn.css +0 -1
- package/src/internal/model-pricing.ts +0 -426
- /package/dist/docs/assets/{example-agents_benny.md.B0gjhI-p.lean.js → example-agents_benny.md.2Et1qa8f.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_bugbot.md.DelIdhxB.lean.js → example-agents_bugbot.md.ByUexi5i.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_concierge.md.4rQTSMXt.lean.js → example-agents_concierge.md.lL8rhYlj.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_fsd.md.CzgUrDfi.lean.js → example-agents_fsd.md.DfNKQTHz.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_oncall.md.BG_sUMly.lean.js → example-agents_oncall.md.wFFXXEyW.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_security-reviewer.md.Dhj_m7_B.lean.js → example-agents_security-reviewer.md.Dkf1gyo6.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_slack-agent.md.buLbgvBf.lean.js → example-agents_slack-agent.md.DvgvT4nn.lean.js} +0 -0
- /package/dist/docs/assets/{guides_agent-to-agent.md.Bpzgq2Pq.lean.js → guides_agent-to-agent.md.Bmbxy-FA.lean.js} +0 -0
- /package/dist/docs/assets/{guides_cloud-runtime.md.gVzabdQL.lean.js → guides_cloud-runtime.md.BZ2GA7Es.lean.js} +0 -0
- /package/dist/docs/assets/{guides_github.md.DOOCpqsW.lean.js → guides_github.md.R2QlpR75.lean.js} +0 -0
- /package/dist/docs/assets/{guides_human-in-the-loop.md.DlUqsp1S.lean.js → guides_human-in-the-loop.md.BWvT7UqY.lean.js} +0 -0
- /package/dist/docs/assets/{guides_webhooks.md.wSOYas3X.lean.js → guides_webhooks.md.DiAwSR42.lean.js} +0 -0
- /package/dist/docs/assets/{hillclimbing.md.DHNast08.lean.js → hillclimbing.md.D9Y1_bYh.lean.js} +0 -0
- /package/dist/docs/assets/{quickstart.md.BU6Iwi_9.lean.js → quickstart.md.TnEXYgYW.lean.js} +0 -0
- /package/dist/docs/assets/{reference_agent-config.md.DrW2JUM8.lean.js → reference_agent-config.md.kuN6-OxK.lean.js} +0 -0
- /package/dist/docs/assets/{reference_connections.md.B9Q3TOve.lean.js → reference_connections.md.DGqAsFXb.lean.js} +0 -0
- /package/dist/docs/assets/{reference_http-api.md.BncLd3PZ.lean.js → reference_http-api.md.CfVM_ICa.lean.js} +0 -0
- /package/dist/docs/assets/{reference_schedules.md.w_F2mXB6.lean.js → reference_schedules.md.gmfYzf_I.lean.js} +0 -0
- /package/dist/docs/assets/{reference_sessions.md.DLd6mvbv.lean.js → reference_sessions.md.C_ouF_uf.lean.js} +0 -0
- /package/dist/docs/assets/{reference_tools.md.BRSDnTbN.lean.js → reference_tools.md.BswAQM41.lean.js} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import{_ as t,c as s,o as a,ag as n}from"./chunks/framework.CAZyNGu9.js";const g=JSON.parse('{"title":"Agent-to-agent","description":"Every agent is an MCP server. Peer MCP connections let one agent delegate to another that keeps its own tools, sessions, and context.","frontmatter":{"title":"Agent-to-agent","description":"Every agent is an MCP server. Peer MCP connections let one agent delegate to another that keeps its own tools, sessions, and context."},"headers":[],"relativePath":"guides/agent-to-agent.md","filePath":"guides/agent-to-agent.md"}'),o={name:"guides/agent-to-agent.md"};function i(r,e,h,l,d,c){return a(),s("div",null,[...e[0]||(e[0]=[n(`<h1 id="agent-to-agent" tabindex="-1">Agent-to-agent <a class="header-anchor" href="#agent-to-agent" aria-label="Permalink to "Agent-to-agent""></a></h1><p>Every mounted agent is also an MCP server. So agents can delegate to each other without extra infrastructure. One agent hands a question to another, and the peer answers in its own session with its own instructions, tools, and context. Any external MCP client can do the same. A peer MCP connection makes the wiring one line.</p><p>This guide wires a <code>concierge</code> agent that delegates weather questions to a <code>weather-agent</code> peer mounted on the same host.</p><h2 id="the-mcp-endpoint" tabindex="-1">The MCP endpoint <a class="header-anchor" href="#the-mcp-endpoint" aria-label="Permalink to "The MCP endpoint""></a></h2><p>Each agent serves the Model Context Protocol over streamable HTTP at <code>/<slug>/v1/mcp</code> (or <code>/v1/mcp</code> in single mode). The surface is stateless (session identity travels in tool arguments) and runs the same route auth chain as the session API. It exposes three tools:</p><table tabindex="0"><thead><tr><th>Tool</th><th>Behavior</th></tr></thead><tbody><tr><td><code>ask</code></td><td>Send a message. Runs a model turn in this agent's own session and returns <code>{ status, sessionId, reply }</code>. Omit <code>sessionId</code> for a fresh session; pass it back to follow up.</td></tr><tr><td><code>check</code></td><td>Wait for or poll a running session (<code>waitSeconds: 0</code> polls without blocking).</td></tr><tr><td><code>call_tool</code></td><td>Call one of the agent's server tools directly, no model turn. Registered only when the agent has server tools.</td></tr></tbody></table><p>Waits are bounded at roughly 50 seconds, below typical MCP client request timeouts: a long turn returns <code>status: "running"</code> and the caller keeps waiting with <code>check</code>. Sessions created this way live on the <code>mcp</code> channel, bind to the calling principal, and show up in the playground and <code>GET /v1/sessions</code> like any other session.</p><p>Any MCP client can attach to this endpoint. It isn't only for other
|
|
1
|
+
import{_ as t,c as s,o as a,ag as n}from"./chunks/framework.CAZyNGu9.js";const g=JSON.parse('{"title":"Agent-to-agent","description":"Every agent is an MCP server. Peer MCP connections let one agent delegate to another that keeps its own tools, sessions, and context.","frontmatter":{"title":"Agent-to-agent","description":"Every agent is an MCP server. Peer MCP connections let one agent delegate to another that keeps its own tools, sessions, and context."},"headers":[],"relativePath":"guides/agent-to-agent.md","filePath":"guides/agent-to-agent.md"}'),o={name:"guides/agent-to-agent.md"};function i(r,e,h,l,d,c){return a(),s("div",null,[...e[0]||(e[0]=[n(`<h1 id="agent-to-agent" tabindex="-1">Agent-to-agent <a class="header-anchor" href="#agent-to-agent" aria-label="Permalink to "Agent-to-agent""></a></h1><p>Every mounted agent is also an MCP server. So agents can delegate to each other without extra infrastructure. One agent hands a question to another, and the peer answers in its own session with its own instructions, tools, and context. Any external MCP client can do the same. A peer MCP connection makes the wiring one line.</p><p>This guide wires a <code>concierge</code> agent that delegates weather questions to a <code>weather-agent</code> peer mounted on the same host.</p><h2 id="the-mcp-endpoint" tabindex="-1">The MCP endpoint <a class="header-anchor" href="#the-mcp-endpoint" aria-label="Permalink to "The MCP endpoint""></a></h2><p>Each agent serves the Model Context Protocol over streamable HTTP at <code>/<slug>/v1/mcp</code> (or <code>/v1/mcp</code> in single mode). The surface is stateless (session identity travels in tool arguments) and runs the same route auth chain as the session API. It exposes three tools:</p><table tabindex="0"><thead><tr><th>Tool</th><th>Behavior</th></tr></thead><tbody><tr><td><code>ask</code></td><td>Send a message. Runs a model turn in this agent's own session and returns <code>{ status, sessionId, reply }</code>. Omit <code>sessionId</code> for a fresh session; pass it back to follow up.</td></tr><tr><td><code>check</code></td><td>Wait for or poll a running session (<code>waitSeconds: 0</code> polls without blocking).</td></tr><tr><td><code>call_tool</code></td><td>Call one of the agent's server tools directly, no model turn. Registered only when the agent has server tools.</td></tr></tbody></table><p>Waits are bounded at roughly 50 seconds, below typical MCP client request timeouts: a long turn returns <code>status: "running"</code> and the caller keeps waiting with <code>check</code>. Sessions created this way live on the <code>mcp</code> channel, bind to the calling principal, and show up in the playground and <code>GET /v1/sessions</code> like any other session.</p><p>Any MCP client can attach to this endpoint. It isn't only for other Agent SDK agents.</p><h2 id="wire-a-peer-mcp-connection" tabindex="-1">Wire a peer MCP connection <a class="header-anchor" href="#wire-a-peer-mcp-connection" aria-label="Permalink to "Wire a peer MCP connection""></a></h2><p>A peer MCP connection points one agent at another mounted on the same serve host. Author an MCP connection whose transport is the peer's slug:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// agents/concierge/agent/mcp-connections/weather.ts</span></span>
|
|
2
2
|
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { defineConnection } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "@cursor/july/connections"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
|
3
3
|
<span class="line"></span>
|
|
4
4
|
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineConnection</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
5
5
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> agent: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"weather-agent"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
6
6
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> description: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"Delegate weather questions to the weather agent."</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
7
|
-
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>The parent model now sees the peer's <code>ask</code> and <code>check</code> (and <code>call_tool</code>) tools under the <code>weather</code> server name. It reads like subagent delegation, except the peer is a full agent that keeps its own instructions, tools, MCP connections, and sessions.</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">
|
|
8
|
-
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">
|
|
7
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>The parent model now sees the peer's <code>ask</code> and <code>check</code> (and <code>call_tool</code>) tools under the <code>weather</code> server name. It reads like subagent delegation, except the peer is a full agent that keeps its own instructions, tools, MCP connections, and sessions.</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> serve</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ./agents</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dev</span></span>
|
|
8
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> chat</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --url</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> http://127.0.0.1:3000/concierge</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> \\</span></span>
|
|
9
9
|
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --message</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "What's the weather in Paris right now?"</span></span>
|
|
10
|
-
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># concierge → weather.ask → weather-agent's own session/tools → reply</span></span></code></pre></div><h2 id="peer-or-subagent" tabindex="-1">Peer or subagent? <a class="header-anchor" href="#peer-or-subagent" aria-label="Permalink to "Peer or subagent?""></a></h2><p>The two delegation mechanisms solve different problems.</p><table tabindex="0"><thead><tr><th></th><th>Subagent (<code>agent/subagents/<id>/</code>)</th><th>Peer (<code>defineConnection({ agent })</code>)</th></tr></thead><tbody><tr><td>Runs as</td><td>an SDK custom subagent inside the parent's harness</td><td>an independent agent on the same host</td></tr><tr><td>Own tools, MCP connections, sessions</td><td>no, inherits the parent's surface</td><td>yes, everything is its own</td></tr><tr><td>Visible to others</td><td>only its parent</td><td>any MCP client, other agents, its own playground</td></tr><tr><td>Reach for it when</td><td>splitting one job into specialist roles</td><td>composing independently useful agents</td></tr></tbody></table><h2 id="how-peer-urls-resolve" tabindex="-1">How peer URLs resolve <a class="header-anchor" href="#how-peer-urls-resolve" aria-label="Permalink to "How peer URLs resolve""></a></h2><p>Peer URLs resolve when the server starts, so the ephemeral ports <code>run</code> and <code>eval</code> use work too. Local-runtime turns (and host-side <code>ctx.host.mcp</code> or channel-handler calls) reach the peer over loopback, which works under the default auth. Cloud-runtime turns execute on a VM that cannot reach this host's loopback address: pass <code>--public-url https://
|
|
10
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># concierge → weather.ask → weather-agent's own session/tools → reply</span></span></code></pre></div><h2 id="peer-or-subagent" tabindex="-1">Peer or subagent? <a class="header-anchor" href="#peer-or-subagent" aria-label="Permalink to "Peer or subagent?""></a></h2><p>The two delegation mechanisms solve different problems.</p><table tabindex="0"><thead><tr><th></th><th>Subagent (<code>agent/subagents/<id>/</code>)</th><th>Peer (<code>defineConnection({ agent })</code>)</th></tr></thead><tbody><tr><td>Runs as</td><td>an SDK custom subagent inside the parent's harness</td><td>an independent agent on the same host</td></tr><tr><td>Own tools, MCP connections, sessions</td><td>no, inherits the parent's surface</td><td>yes, everything is its own</td></tr><tr><td>Visible to others</td><td>only its parent</td><td>any MCP client, other agents, its own playground</td></tr><tr><td>Reach for it when</td><td>splitting one job into specialist roles</td><td>composing independently useful agents</td></tr></tbody></table><h2 id="how-peer-urls-resolve" tabindex="-1">How peer URLs resolve <a class="header-anchor" href="#how-peer-urls-resolve" aria-label="Permalink to "How peer URLs resolve""></a></h2><p>Peer URLs resolve when the server starts, so the ephemeral ports <code>run</code> and <code>eval</code> use work too. Local-runtime turns (and host-side <code>ctx.host.mcp</code> or channel-handler calls) reach the peer over loopback, which works under the default auth. Cloud-runtime turns execute on a VM that cannot reach this host's loopback address: pass <code>--public-url https://agent-sdk.example.com</code> (or <code>serve(dir, { publicUrl })</code>) so peers resolve to a reachable URL. Without one, peers are omitted from cloud turns and the server warns at startup. With <code>--bearer-token</code>, the token is attached to peer calls automatically so they pass the target agent's auth chain.</p><h2 id="guardrails" tabindex="-1">Guardrails <a class="header-anchor" href="#guardrails" aria-label="Permalink to "Guardrails""></a></h2><p>Unknown peer slugs and self-references fail <code>serve</code> at startup, so you find out immediately rather than at delegation time. Peers require the multi-agent layout (each agent mounted under its slug, the default).</p><p>The framework does not provide cross-host loop protection. If agent A's instructions delegate to B and B's delegate back to A, they can recurse. Scope each agent's delegation instructions narrowly. The concierge delegates <em>weather questions</em> to <code>weather-agent</code>, not everything.</p><h2 id="call-a-peer-from-host-code" tabindex="-1">Call a peer from host code <a class="header-anchor" href="#call-a-peer-from-host-code" aria-label="Permalink to "Call a peer from host code""></a></h2><p>Peer MCP connections are ordinary MCP connections, so deterministic host code can use them too. A channel handler or server tool can call <code>host.mcp.callTool("weather", "ask", { message: "…" })</code> without any model turn deciding to. See <a href="./../reference/connections.html#every-mcp-connection-is-available-in-three-places">MCP connections</a> for the three places every MCP connection is available.</p><h2 id="what-s-next" tabindex="-1">What's next <a class="header-anchor" href="#what-s-next" aria-label="Permalink to "What's next""></a></h2><p>Continue with these pages:</p><ul><li><a href="./../reference/connections.html">MCP connections</a>: all four MCP connection transports</li><li><a href="./../reference/subagents.html">Subagents</a>: the in-harness alternative</li><li><a href="./../reference/http-api.html#mcp-endpoint">HTTP API</a>: the endpoint contract</li></ul>`,26)])])}const u=t(o,[["render",i]]);export{g as __pageData,u as default};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{_ as t,c as s,o as a,ag as o}from"./chunks/framework.CAZyNGu9.js";const p=JSON.parse('{"title":"Cloud runtime","description":"Run turns on Cursor cloud agents instead of the local harness: when to switch, what changes, and the patterns that hold up.","frontmatter":{"title":"Cloud runtime","description":"Run turns on Cursor cloud agents instead of the local harness: when to switch, what changes, and the patterns that hold up."},"headers":[],"relativePath":"guides/cloud-runtime.md","filePath":"guides/cloud-runtime.md"}'),n={name:"guides/cloud-runtime.md"};function i(r,e,d,l,c,h){return a(),s("div",null,[...e[0]||(e[0]=[o(`<h1 id="cloud-runtime" tabindex="-1">Cloud runtime <a class="header-anchor" href="#cloud-runtime" aria-label="Permalink to "Cloud runtime""></a></h1><p>By default, turns execute on the Cursor SDK's local harness, on the same machine as the server. Set <code>runtime: "cloud"</code> and turns execute on Cursor cloud agents instead. They're ephemeral VMs that carry a repo checkout, run <code>gh</code>, <code>git</code>, and tests for real, and scale past what one host's disk and CPU can do. The serve host keeps handling routing, host preparation, sessions, and bookkeeping.</p><p>A canonical use is a PR driver whose triage runs on cloud VMs. The patterns in this guide come from running one against real PR traffic.</p><h2 id="when-to-switch" tabindex="-1">When to switch <a class="header-anchor" href="#when-to-switch" aria-label="Permalink to "When to switch""></a></h2><p>A guideline from running PR agents at scale: per-PR worktrees on the serve host don't scale to hundreds of engineers opening PRs. When the job needs a repo checkout at scale, use cloud. The signals:</p><ul><li>The agent must run repo commands (tests, builds, <code>git</code>) against many different refs concurrently.</li><li>Turns are long and heavy, and you don't want them competing with the server for resources.</li><li>The work product is a PR or branch the VM can push, not a local file.</li></ul><p>Stay local when the agent is conversational, tool-driven against APIs, or works over host-prepared evidence. Local turns are cheaper, start faster, and support the full authored surface.</p><h2 id="configure-it" tabindex="-1">Configure it <a class="header-anchor" href="#configure-it" aria-label="Permalink to "Configure it""></a></h2><p>Cloud runtime is two fields on the agent config.</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { defineAgent } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "@cursor/july"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
|
2
|
+
<span class="line"></span>
|
|
3
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineAgent</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
4
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> runtime: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"cloud"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
5
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> cloud: {</span></span>
|
|
6
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> repos: [{ url: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"https://github.com/org/repo"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, startingRef: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"main"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }],</span></span>
|
|
7
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // env / envVars / … forwarded to the Cursor SDK</span></span>
|
|
8
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
9
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>The host must be signed in (<code>agent-sdk login</code> or <code>CURSOR_API_KEY</code>).</p><div class="important custom-block github-alert"><p class="custom-block-title">IMPORTANT</p><p>Cloud agents run against the Cursor backend under the signed-in account, and every wake spends real cloud-agent budget. Decide explicitly what may trigger one.</p></div><h2 id="what-changes-on-cloud" tabindex="-1">What changes on cloud <a class="header-anchor" href="#what-changes-on-cloud" aria-label="Permalink to "What changes on cloud""></a></h2><p>Cloud turns run on a VM without your authored files, so the runtime mapping shifts:</p><table tabindex="0"><thead><tr><th>Folder or file</th><th>Local runtime</th><th>Cloud runtime</th></tr></thead><tbody><tr><td><code>instructions.*</code></td><td><code>AGENTS.md</code> in the session workspace</td><td>prepended to the first prompt</td></tr><tr><td>Server tools (<code>execution: "server"</code>)</td><td>in-process SDK custom tools</td><td>not available</td></tr><tr><td>Agent tools (<code>execution: "agent"</code>)</td><td>scripts in the session workspace</td><td>catalog + script bodies on the first prompt</td></tr><tr><td><code>skills/*</code></td><td><code>.cursor/skills/</code> in the workspace</td><td>only if present in the cloud repo</td></tr><tr><td><code>mcp-connections/*.ts</code></td><td>SDK <code>mcpServers</code></td><td>SDK <code>mcpServers</code> (peers need <code>--public-url</code>)</td></tr><tr><td><code>sandbox/workspace/**</code></td><td>seeded into the session workspace</td><td>ignored</td></tr><tr><td>Tool approvals (<code>needsApproval</code>)</td><td>supported</td><td>not supported</td></tr></tbody></table><p><code>agent-sdk validate</code> warns when <code>runtime: "cloud"</code> is combined with local-only capabilities. Those warnings match this table.</p><p>Two more behaviors are cloud-specific. Sessions persist a separate SDK agent id (<code>bc-…</code>), emitted on the stream as <code>agent.bound</code> with a URL to the cloud conversation. Cloud ids are minted during the first send. And peer MCP connections resolve to <code>--public-url</code> for cloud turns, because a VM cannot reach the host's loopback; without one, peers are omitted from cloud turns and the server warns at startup.</p><h2 id="hybrid-local-agent-cloud-sessions" tabindex="-1">Hybrid: local agent, cloud sessions <a class="header-anchor" href="#hybrid-local-agent-cloud-sessions" aria-label="Permalink to "Hybrid: local agent, cloud sessions""></a></h2><p>A local-runtime agent can still open cloud-attached sessions per send. Channel handlers may pass a <code>cloud</code> block (repos pinned to a PR ref, say) in <code>send</code> options, and Slack handlers may return <code>cloud</code> from a mention hook. A PR driver works this way: chat stays local, and the <code>drive</code> flow attaches the PR to a cloud VM. The agent-level <code>cloud</code> config is the base that per-session options merge over.</p><h2 id="patterns-that-hold-up" tabindex="-1">Patterns that hold up <a class="header-anchor" href="#patterns-that-hold-up" aria-label="Permalink to "Patterns that hold up""></a></h2><p>These come from running a PR driver against real PR traffic:</p><ul><li>One cloud agent per unit of work (per PR, say). Store the <code>bc-…</code> id keyed by the work unit (an affinity store written from an <code>agent.bound</code> hook) so webhook wakes resume the same conversation instead of booting a fresh VM per event.</li><li>Stable continuation keys (<code>pr:owner/repo#N</code>) so every wake lands on the same session within a channel.</li><li>Keep the host deterministic: fetch briefs and metadata on the host, send the VM a compact prompt, and let the VM re-read source of truth with its own <code>gh</code> and <code>git</code> instead of trusting payload snapshots.</li><li>Limit exposure: add repository allowlists on webhook channels, because every wake spends the account's budget.</li></ul><h2 id="verify-cloud-agents" tabindex="-1">Verify cloud agents <a class="header-anchor" href="#verify-cloud-agents" aria-label="Permalink to "Verify cloud agents""></a></h2><p><code>agent-sdk run</code> and <code>eval</code> work unchanged. The trajectory records the same event vocabulary plus <code>agent.bound</code> with the cloud URL, so you can open the cloud conversation for any session. Cloud turns take minutes. Pass generous <code>--timeout-ms</code> values, and keep curl timeouts long when driving channels directly.</p><h2 id="what-s-next" tabindex="-1">What's next <a class="header-anchor" href="#what-s-next" aria-label="Permalink to "What's next""></a></h2><p>Continue with these pages:</p><ul><li><a href="./../reference/agent-config.html">Agent config</a>: the <code>runtime</code> and <code>cloud</code> fields precisely</li><li><a href="./github.html">GitHub guide</a>: the webhook patterns that pair with cloud triage</li></ul>`,27)])])}const g=t(n,[["render",i]]);export{p as __pageData,g as default};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import{_ as e,c as i,o as t,ag as a}from"./chunks/framework.CAZyNGu9.js";const c=JSON.parse('{"title":"GitHub","description":"Wake your agent from pull requests, CI, and comments by pulling Cursor SCM events, with fixtures and replay for local tests.","frontmatter":{"title":"GitHub","description":"Wake your agent from pull requests, CI, and comments by pulling Cursor SCM events, with fixtures and replay for local tests."},"headers":[],"relativePath":"guides/github.md","filePath":"guides/github.md"}'),n={name:"guides/github.md"};function h(o,s,l,r,d,p){return t(),i("div",null,[...s[0]||(s[0]=[a(`<h1 id="github-agents" tabindex="-1">GitHub agents <a class="header-anchor" href="#github-agents" aria-label="Permalink to "GitHub agents""></a></h1><p>Wake your agent from repository events without exposing a public webhook URL. Prefer <code>serve --cursor-events</code>: the host long-polls Cursor's SCM event stream for repos you've connected to Cursor. You still declare a <code>githubChannel</code> so hooks decide what each event does.</p><p>The companion skill for coding agents is <a href="./../../skills/github/SKILL.html"><code>skills/github/SKILL.md</code></a>.</p><h2 id="pull-events-from-cursor" tabindex="-1">Pull events from Cursor <a class="header-anchor" href="#pull-events-from-cursor" aria-label="Permalink to "Pull events from Cursor""></a></h2><p>Connect GitHub in Cursor for the repositories you care about (Settings or <a href="https://cursor.com/dashboard" target="_blank" rel="noreferrer">cursor.com/dashboard</a>). That gives your account access and lets Cursor receive the repo's webhooks. Sign the host in (<code>
|
|
1
|
+
import{_ as e,c as i,o as t,ag as a}from"./chunks/framework.CAZyNGu9.js";const c=JSON.parse('{"title":"GitHub","description":"Wake your agent from pull requests, CI, and comments by pulling Cursor SCM events, with fixtures and replay for local tests.","frontmatter":{"title":"GitHub","description":"Wake your agent from pull requests, CI, and comments by pulling Cursor SCM events, with fixtures and replay for local tests."},"headers":[],"relativePath":"guides/github.md","filePath":"guides/github.md"}'),n={name:"guides/github.md"};function h(o,s,l,r,d,p){return t(),i("div",null,[...s[0]||(s[0]=[a(`<h1 id="github-agents" tabindex="-1">GitHub agents <a class="header-anchor" href="#github-agents" aria-label="Permalink to "GitHub agents""></a></h1><p>Wake your agent from repository events without exposing a public webhook URL. Prefer <code>serve --cursor-events</code>: the host long-polls Cursor's SCM event stream for repos you've connected to Cursor. You still declare a <code>githubChannel</code> so hooks decide what each event does.</p><p>The companion skill for coding agents is <a href="./../../skills/github/SKILL.html"><code>skills/github/SKILL.md</code></a>.</p><h2 id="pull-events-from-cursor" tabindex="-1">Pull events from Cursor <a class="header-anchor" href="#pull-events-from-cursor" aria-label="Permalink to "Pull events from Cursor""></a></h2><p>Connect GitHub in Cursor for the repositories you care about (Settings or <a href="https://cursor.com/dashboard" target="_blank" rel="noreferrer">cursor.com/dashboard</a>). That gives your account access and lets Cursor receive the repo's webhooks. Sign the host in (<code>agent-sdk login</code> or <code>CURSOR_API_KEY</code>), then opt the channel into the Cursor account connection:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> githubChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
2
2
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> cursorAccount: {</span></span>
|
|
3
3
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> repos: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"owner/repo"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">],</span></span>
|
|
4
4
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // permissions?: "read" | "pr-write" | "contents-write"</span></span>
|
|
5
5
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // default "pr-write" (comments / PR writes, no contents:write)</span></span>
|
|
6
6
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
7
7
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // hooks...</span></span>
|
|
8
|
-
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p><code>cursorAccount</code> starts the event relay and mints one short-lived GitHub credential scoped to those repositories. <code>ctx.github</code>, <code>ctx.host.github</code>, and child <code>gh</code> commands share it.
|
|
8
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p><code>cursorAccount</code> starts the event relay and mints one short-lived GitHub credential scoped to those repositories. <code>ctx.github</code>, <code>ctx.host.github</code>, and child <code>gh</code> commands share it. The Agent SDK refreshes the credential before expiry. No GitHub App key, PAT, or separate <code>gh auth login</code> is needed on the host.</p><p>Choose <code>permissions</code> by what the agent needs:</p><table tabindex="0"><thead><tr><th><code>permissions</code></th><th>Use when</th></tr></thead><tbody><tr><td><code>"read"</code></td><td>Inspect PRs / issues / statuses only</td></tr><tr><td><code>"pr-write"</code> (default)</td><td>Comment, review, update PR/issue metadata</td></tr><tr><td><code>"contents-write"</code></td><td>Push code (<code>contents:write</code>)</td></tr></tbody></table><p><code>contents-write</code> is an explicit opt-up. The host holds a push-capable token shared with model-driven tools and untrusted webhook content — prefer <code>"pr-write"</code> unless the agent must push.</p><p>Selected repositories must share one GitHub owner (one App installation). Configuration that spans owners fails at startup / mint time.</p><p>To keep repository scope in deployment config instead, use <code>cursorAccount: true</code> and pass it at serve time:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> serve</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --cursor-events</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --repo</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> owner/repo</span></span></code></pre></div><p>Repeat <code>--repo</code> for each repository. The stream and credential are resolved as the signed-in Cursor principal. <code>serve</code> refuses to start signed out.</p><p>Offset and consumer id live under <code><state-root>/cursor-events/</code>. <code>CURSOR_API_BASE_URL</code> overrides the backend. The stream carries event metadata, not full webhook bodies, so your agent should re-read the PR or checks from GitHub instead of trusting a snapshot in the wake.</p><p>This is the preferred production path: no public URL, no repo admin webhook, and no inbound network for GitHub deliveries.</p><h2 id="define-the-channel" tabindex="-1">Define the channel <a class="header-anchor" href="#define-the-channel" aria-label="Permalink to "Define the channel""></a></h2><p>Author <code>agent/channels/github.ts</code> with <code>githubChannel()</code> from <code>@cursor/july/channels/github</code>. It mounts <code>POST /<slug>/v1/channels/github</code> and publishes the events it dispatches on. That event set comes from the hooks you declare, or you pin it with <code>webhookEvents</code>. Cursor event pull and local replay both use it.</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { defaultGitHubAuth, githubChannel } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "@cursor/july/channels/github"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
|
9
9
|
<span class="line"></span>
|
|
10
10
|
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> githubChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
11
11
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> botName: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"my-agent"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// or GITHUB_APP_SLUG; used to ignore self-comments</span></span>
|
|
@@ -18,10 +18,10 @@ import{_ as e,c as i,o as t,ag as a}from"./chunks/framework.CAZyNGu9.js";const c
|
|
|
18
18
|
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -H</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'content-type: application/json'</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> \\</span></span>
|
|
19
19
|
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -H</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'x-github-event: pull_request'</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> \\</span></span>
|
|
20
20
|
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -d</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @fixtures/github/pull_request.synchronize.json</span></span></code></pre></div><p>Don't hand-write payloads. Snapshot real ones with replay's <code>--dry-run --out</code>, below.</p><h3 id="test-with-github-replay" tabindex="-1">Test with <code>github replay</code> <a class="header-anchor" href="#test-with-github-replay" aria-label="Permalink to "Test with \`github replay\`""></a></h3><p>Use <code>replay</code> for deterministic tests and <a href="./../hillclimbing.html">hillclimbing</a>. It reads a real PR with <code>gh api</code>, synthesizes GitHub-shaped payloads, signs them when a secret is configured, and POSTs them at the channel. Pull access is enough: no admin, and an env <code>GITHUB_TOKEN</code> is fine here. The same input produces the same delivery.</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># Replay a pull_request delivery for a PR</span></span>
|
|
21
|
-
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">
|
|
21
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> github</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> replay</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> https://github.com/owner/repo/pull/123</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span></span>
|
|
22
22
|
<span class="line"></span>
|
|
23
23
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># Replay everything the channel listens for, with CI failing</span></span>
|
|
24
|
-
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">
|
|
24
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> github</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> replay</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> owner/repo#123</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --events</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '*'</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --conclusion</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> failure</span></span>
|
|
25
25
|
<span class="line"></span>
|
|
26
26
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># Inspect payloads without POSTing, and snapshot them as fixtures</span></span>
|
|
27
|
-
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">
|
|
27
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> github</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> replay</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> owner/repo#123</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --events</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> '*'</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dry-run</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --out</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> fixtures/github</span></span></code></pre></div><p><code>--events</code> defaults to <code>pull_request</code>, and <code>'*'</code> means the channel's declared set. <code>--action</code>, <code>--conclusion</code>, <code>--comment</code>, and <code>--context</code> shape each synthesized event. <code>--secret</code> (or <code>GITHUB_WEBHOOK_SECRET</code>) signs them.</p><h2 id="receive-webhooks-directly" tabindex="-1">Receive webhooks directly <a class="header-anchor" href="#receive-webhooks-directly" aria-label="Permalink to "Receive webhooks directly""></a></h2><p>Most hosts should pull events from Cursor instead. Use the HTTP channel route when you already terminate GitHub webhooks yourself, or when you are POSTing fixtures and replay locally.</p><p>With a webhook secret configured, the route admits everyone (<code>allowAll()</code>) and the channel verifies <code>X-Hub-Signature-256</code> before parsing. The HMAC becomes the request principal. Without a secret, the route is loopback-only. The exception is <code>serve --dev</code>, which admits unsigned loopback deliveries so fixtures and replay work with zero config. Non-dev targets that accept real GitHub POSTs always need the secret, and the same value must live on the server and on whatever signs deliveries.</p><h2 id="handle-high-event-volume" tabindex="-1">Handle high event volume <a class="header-anchor" href="#handle-high-event-volume" aria-label="Permalink to "Handle high event volume""></a></h2><p>These patterns come from running a PR agent against real traffic:</p><ul><li>Debounce per PR (~3 seconds, latest event wins), and re-buffer while CI settles. Skip a flush when a turn for that PR is already running.</li><li>Persist the buffer before you acknowledge a wake, and restore it on channel start. A restart must not drop buffered wakes.</li><li>Key sessions with a stable continuation token (<code>pr:owner/repo#N</code>) so every wake resumes the PR's conversation. Cross-channel resume needs an affinity store mapping PR → SDK agent id; write one from an <code>agent.bound</code> hook.</li><li>Keep payload details out of wake prompts. Send a generic "re-check the PR" and let the agent re-read source of truth instead of trusting a stale snapshot.</li><li>Cancel PR-scoped reminders on <code>pull_request.closed</code>.</li><li>Decide explicitly which repos the agent may act on. Without an allowlist the channel wakes for whatever deliveries reach it, and every wake spends real model budget.</li></ul><h2 id="related" tabindex="-1">Related <a class="header-anchor" href="#related" aria-label="Permalink to "Related""></a></h2><ul><li><a href="./webhooks.html">Webhooks and custom channels</a>: the HTTP mechanism under this pack</li><li><a href="./../evals.html">Evals</a>: turn replay snapshots into regression fixtures</li><li><a href="./cloud-runtime.html">Cloud runtime</a>: attach PRs to cloud VMs</li></ul>`,41)])])}const u=e(n,[["render",h]]);export{c as __pageData,u as default};
|
|
@@ -25,4 +25,4 @@ import{_ as a,c as i,o as e,ag as t}from"./chunks/framework.CAZyNGu9.js";const c
|
|
|
25
25
|
<span class="line"></span>
|
|
26
26
|
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
27
27
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> toolApprovals: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
28
|
-
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>The Slack app manifest needs interactivity enabled. Cards show redacted, truncated arguments because of Block Kit size limits. Execution still uses the full validated input, so review sensitive tools in the playground when the arguments may exceed the card. Details in the <a href="./slack.html#add-approval-buttons">Slack guide</a>.</p><p>In <code>serve --dev</code>, the playground can also list Slack sessions and resolve their parked tools (the audit trail records the HTTP caller). That bridge does not open cross-owner approval for HTTP sessions, and production and bearer-auth hosts stay strict: Slack approvals must come from Slack interactivity or a matching principal.</p><h2 id="design-principles-for-approvals" tabindex="-1">Design principles for approvals <a class="header-anchor" href="#design-principles-for-approvals" aria-label="Permalink to "Design principles for approvals""></a></h2><p>Park/resume is independent of delivery: <code>needsApproval</code> works with no Slack channel at all, because the playground and HTTP surfaces are always there.</p><p>Prefer approval gates over trust in instructions. "Only call this tool when…" is a suggestion; <code>needsApproval</code> is a guarantee. And pair approvals with dry-run defaults for destructive integrations: post real PR reviews only behind an explicit env flag like <code>MY_AGENT_LIVE=1</code>, no matter who approved.</p><p>Deterministic tool calls (<code>
|
|
28
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>The Slack app manifest needs interactivity enabled. Cards show redacted, truncated arguments because of Block Kit size limits. Execution still uses the full validated input, so review sensitive tools in the playground when the arguments may exceed the card. Details in the <a href="./slack.html#add-approval-buttons">Slack guide</a>.</p><p>In <code>serve --dev</code>, the playground can also list Slack sessions and resolve their parked tools (the audit trail records the HTTP caller). That bridge does not open cross-owner approval for HTTP sessions, and production and bearer-auth hosts stay strict: Slack approvals must come from Slack interactivity or a matching principal.</p><h2 id="design-principles-for-approvals" tabindex="-1">Design principles for approvals <a class="header-anchor" href="#design-principles-for-approvals" aria-label="Permalink to "Design principles for approvals""></a></h2><p>Park/resume is independent of delivery: <code>needsApproval</code> works with no Slack channel at all, because the playground and HTTP surfaces are always there.</p><p>Prefer approval gates over trust in instructions. "Only call this tool when…" is a suggestion; <code>needsApproval</code> is a guarantee. And pair approvals with dry-run defaults for destructive integrations: post real PR reviews only behind an explicit env flag like <code>MY_AGENT_LIVE=1</code>, no matter who approved.</p><p>Deterministic tool calls (<code>agent-sdk call</code>, <code>POST /v1/tools/:name</code>) execute directly without parking. There the human is the caller. Approval parking applies to model-initiated calls.</p><h2 id="what-s-next" tabindex="-1">What's next <a class="header-anchor" href="#what-s-next" aria-label="Permalink to "What's next""></a></h2><p>Continue with these pages:</p><ul><li><a href="./../reference/tools.html">Tools</a>: the full tool API <code>needsApproval</code> lives on</li><li><a href="./slack.html">Slack</a>: the approval cards in context</li><li><a href="./../reference/sessions.html">Sessions and streaming</a>: the <code>action.approval_*</code> events on the wire</li></ul>`,27)])])}const u=a(n,[["render",l]]);export{c as __pageData,u as default};
|
package/dist/docs/assets/{guides_mcp-oauth.md.Dd8EgSem.js → guides_mcp-oauth.md.C7G7IykG.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Host MCP OAuth","description":"Authorize defineConnection({ url, oauth: true }) with
|
|
1
|
+
import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Host MCP OAuth","description":"Authorize defineConnection({ url, oauth: true }) with agent-sdk mcp oauth, store tokens locally, and push MCP_OAUTH_* secrets to hosted deployments.","frontmatter":{"title":"Host MCP OAuth","description":"Authorize defineConnection({ url, oauth: true }) with agent-sdk mcp oauth, store tokens locally, and push MCP_OAUTH_* secrets to hosted deployments."},"headers":[],"relativePath":"guides/mcp-oauth.md","filePath":"guides/mcp-oauth.md"}'),n={name:"guides/mcp-oauth.md"};function o(h,s,l,d,r,p){return a(),t("div",null,[...s[0]||(s[0]=[i(`<h1 id="host-mcp-oauth" tabindex="-1">Host MCP OAuth <a class="header-anchor" href="#host-mcp-oauth" aria-label="Permalink to "Host MCP OAuth""></a></h1><p>Use host MCP OAuth when your agent talks to a remote MCP server that speaks OAuth, and you want credentials on the serve host (or the hosted engine) instead of a Cursor account connector. Local login writes tokens next to your Cursor credentials. <code>--store</code> copies them onto the deployment as secrets so prod can reconnect after a redeploy.</p><p>The companion skill is <a href="./../../skills/mcp-auth/SKILL.html"><code>skills/mcp-auth/SKILL.md</code></a>.</p><h2 id="what-can-host-mcp-oauth-do" tabindex="-1">What can host MCP OAuth do? <a class="header-anchor" href="#what-can-host-mcp-oauth-do" aria-label="Permalink to "What can host MCP OAuth do?""></a></h2><ul><li>Authorize <code>defineConnection({ url, oauth: true })</code> with a browser PKCE flow (<code>agent-sdk mcp oauth <connection></code>)</li><li>Keep tokens in <code>~/.config/agent-serve/mcp-auth.json</code>, bound to that connection's resource URL</li><li>Upsert deployment secrets with <code>--store</code> so hosted engines seed the same tokens from env</li><li>Keep privileged servers off the model with <code>hostOnly: true</code> while tools still call them through <code>ctx.host.mcp</code></li></ul><p>Prefer a Cursor account MCP connection when the connector already lives in the signed-in account dashboard:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">defineConnection</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ cursorAccount: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }) </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// every connected connector</span></span>
|
|
2
2
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// or servers: "*" / servers: ["Linear"]</span></span></code></pre></div><p>Use host OAuth when the server is yours (or private to your network) and the host must hold tokens.</p><h2 id="how-do-i-declare-a-host-oauth-connection" tabindex="-1">How do I declare a host-OAuth connection? <a class="header-anchor" href="#how-do-i-declare-a-host-oauth-connection" aria-label="Permalink to "How do I declare a host-OAuth connection?""></a></h2><p>Add one file under <code>agent/mcp-connections/</code>. The filename is the connection name you pass to the CLI and to <code>host.mcp</code>.</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// agent/mcp-connections/inventory.ts</span></span>
|
|
3
3
|
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { defineConnection } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "@cursor/july/connections"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
|
4
4
|
<span class="line"></span>
|
|
@@ -8,7 +8,7 @@ import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.CAZyNGu9.js";const k
|
|
|
8
8
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> hostOnly: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
9
9
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> description:</span></span>
|
|
10
10
|
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "Inventory MCP (privileged). Call only from host tools, not the model."</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
11
|
-
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Rules of the road:</p><ul><li><code>oauth: true</code> is required for <code>
|
|
11
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Rules of the road:</p><ul><li><code>oauth: true</code> is required for <code>agent-sdk mcp oauth</code></li><li><code>hostOnly: true</code> hides the server from the model; <code>ctx.host.mcp</code> and channel handlers still see it</li><li>Declare expected secret names on the agent when you plan to <code>--store</code>:</li></ul><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// agent/agent.ts</span></span>
|
|
12
12
|
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineAgent</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
13
13
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // …</span></span>
|
|
14
14
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> hosting: {</span></span>
|
|
@@ -20,11 +20,11 @@ import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.CAZyNGu9.js";const k
|
|
|
20
20
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // Hosted engines need an explicit allowlist for non-bootstrap hosts.</span></span>
|
|
21
21
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> egressDomains: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"mcp.example.com"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">],</span></span>
|
|
22
22
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
23
|
-
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Secret names follow <code>MCP_OAUTH_<CONNECTION>_*</code> where <code><CONNECTION></code> is the connection filename uppercased with non-alphanumerics turned into underscores (<code>inventory</code> → <code>MCP_OAUTH_INVENTORY_…</code>).</p><h2 id="how-do-i-authorize-locally" tabindex="-1">How do I authorize locally? <a class="header-anchor" href="#how-do-i-authorize-locally" aria-label="Permalink to "How do I authorize locally?""></a></h2><p>From the agent project (Node 22.13+, not Bun):</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">
|
|
23
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Secret names follow <code>MCP_OAUTH_<CONNECTION>_*</code> where <code><CONNECTION></code> is the connection filename uppercased with non-alphanumerics turned into underscores (<code>inventory</code> → <code>MCP_OAUTH_INVENTORY_…</code>).</p><h2 id="how-do-i-authorize-locally" tabindex="-1">How do I authorize locally? <a class="header-anchor" href="#how-do-i-authorize-locally" aria-label="Permalink to "How do I authorize locally?""></a></h2><p>From the agent project (Node 22.13+, not Bun):</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> mcp</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> oauth</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> inventory</span></span></code></pre></div><p>What happens:</p><ol><li>The Agent SDK loads <code>agent/mcp-connections/inventory.ts</code> and checks <code>oauth: true</code></li><li>It opens the authorization URL in your browser</li><li>The callback lands on <code>http://localhost:8787/callback</code></li><li>Tokens land in <code>~/.config/agent-serve/mcp-auth.json</code> (override the config dir with <code>AGENT_SERVE_CONFIG_DIR</code>)</li></ol><p>If you're already authorized, the command prints that and exits. Re-run it after rotating tokens on the MCP server, or after you change the connection URL (tokens are bound to the resource URL).</p><h2 id="how-do-i-store-credentials-on-a-hosted-deployment" tabindex="-1">How do I store credentials on a hosted deployment? <a class="header-anchor" href="#how-do-i-store-credentials-on-a-hosted-deployment" aria-label="Permalink to "How do I store credentials on a hosted deployment?""></a></h2><p>Authorize once, then push secrets to the deployment:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> mcp</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> oauth</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> inventory</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --store</span></span>
|
|
24
24
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># optional:</span></span>
|
|
25
25
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># --slug my-agent</span></span>
|
|
26
|
-
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># --team <cursor-team-id></span></span></code></pre></div><p><code>--store</code> upserts:</p><table tabindex="0"><thead><tr><th>Secret</th><th>Source</th></tr></thead><tbody><tr><td><code>MCP_OAUTH_<NAME>_ACCESS_TOKEN</code></td><td>access token (required)</td></tr><tr><td><code>MCP_OAUTH_<NAME>_REFRESH_TOKEN</code></td><td>refresh token when the server returns one</td></tr><tr><td><code>MCP_OAUTH_<NAME>_CLIENT_ID</code></td><td>dynamic client id when registration returned one</td></tr></tbody></table><p>You must be signed in (<code>
|
|
26
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># --team <cursor-team-id></span></span></code></pre></div><p><code>--store</code> upserts:</p><table tabindex="0"><thead><tr><th>Secret</th><th>Source</th></tr></thead><tbody><tr><td><code>MCP_OAUTH_<NAME>_ACCESS_TOKEN</code></td><td>access token (required)</td></tr><tr><td><code>MCP_OAUTH_<NAME>_REFRESH_TOKEN</code></td><td>refresh token when the server returns one</td></tr><tr><td><code>MCP_OAUTH_<NAME>_CLIENT_ID</code></td><td>dynamic client id when registration returned one</td></tr></tbody></table><p>You must be signed in (<code>agent-sdk login</code>) with permission to set secrets on that slug. Secrets apply on the <strong>next</strong> deploy; run <code>agent-sdk deploy</code> (or wait for your usual deploy path) after <code>--store</code>.</p><p>On the engine, when <code>mcp-auth.json</code> is empty, serve seeds the OAuth provider from those env vars so host MCP calls work without a browser on the pod.</p><h2 id="how-do-host-tools-call-the-server" tabindex="-1">How do host tools call the server? <a class="header-anchor" href="#how-do-host-tools-call-the-server" aria-label="Permalink to "How do host tools call the server?""></a></h2><p>Keep privileged calls on the host:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> result</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ctx.host.mcp.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">callTool</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
|
|
27
27
|
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "inventory"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
28
28
|
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "list_warehouses"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
29
29
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { region: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"us-east"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
|
30
|
-
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span></code></pre></div><p>The model never sees <code>hostOnly</code> tools in its MCP namespace list. If the agent asks to "check IDE MCP" or run <code>mcp_auth</code>, point it at your host tool instead.</p><h2 id="what-if-authorization-fails" tabindex="-1">What if authorization fails? <a class="header-anchor" href="#what-if-authorization-fails" aria-label="Permalink to "What if authorization fails?""></a></h2><table tabindex="0"><thead><tr><th>What you see</th><th>What to do</th></tr></thead><tbody><tr><td><code>must be defineConnection({ url, oauth: true })</code></td><td>Add <code>oauth: true</code> on that connection, or pick the right connection name</td></tr><tr><td>Callback never completes</td><td>Keep port <code>8787</code> free; finish the browser login on this machine</td></tr><tr><td>Hosted calls unauthorized after <code>--store</code></td><td>Confirm secrets with <code>
|
|
30
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span></code></pre></div><p>The model never sees <code>hostOnly</code> tools in its MCP namespace list. If the agent asks to "check IDE MCP" or run <code>mcp_auth</code>, point it at your host tool instead.</p><h2 id="what-if-authorization-fails" tabindex="-1">What if authorization fails? <a class="header-anchor" href="#what-if-authorization-fails" aria-label="Permalink to "What if authorization fails?""></a></h2><table tabindex="0"><thead><tr><th>What you see</th><th>What to do</th></tr></thead><tbody><tr><td><code>must be defineConnection({ url, oauth: true })</code></td><td>Add <code>oauth: true</code> on that connection, or pick the right connection name</td></tr><tr><td>Callback never completes</td><td>Keep port <code>8787</code> free; finish the browser login on this machine</td></tr><tr><td>Hosted calls unauthorized after <code>--store</code></td><td>Confirm secrets with <code>agent-sdk secrets list <slug></code>, then redeploy</td></tr><tr><td>Tokens ignored after URL change</td><td>Expected: resource URL binding drops stale entries. Re-run <code>mcp oauth</code></td></tr></tbody></table><h2 id="what-s-next" tabindex="-1">What's next <a class="header-anchor" href="#what-s-next" aria-label="Permalink to "What's next""></a></h2><ul><li><a href="./../reference/connections.html">MCP connections</a>: transports, <code>hostOnly</code>, account MCP</li><li><a href="./../reference/cli.html#mcp-oauth">CLI</a>: full flag list for <code>mcp oauth</code></li><li><a href="./../deployment.html">Deployment</a>: secrets, egress, and hosted engines</li><li><a href="./../troubleshooting.html">Fix common agent problems</a>: more symptom → fix tables</li></ul>`,36)])])}const u=e(n,[["render",o]]);export{k as __pageData,u as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as e,c as t,o as a,ag as i}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Host MCP OAuth","description":"Authorize defineConnection({ url, oauth: true }) with agent-sdk mcp oauth, store tokens locally, and push MCP_OAUTH_* secrets to hosted deployments.","frontmatter":{"title":"Host MCP OAuth","description":"Authorize defineConnection({ url, oauth: true }) with agent-sdk mcp oauth, store tokens locally, and push MCP_OAUTH_* secrets to hosted deployments."},"headers":[],"relativePath":"guides/mcp-oauth.md","filePath":"guides/mcp-oauth.md"}'),n={name:"guides/mcp-oauth.md"};function o(h,s,l,d,r,p){return a(),t("div",null,[...s[0]||(s[0]=[i("",36)])])}const u=e(n,[["render",o]]);export{k as __pageData,u as default};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const c=JSON.parse('{"title":"Slack","description":"Put the agent in Slack over Socket Mode: Add to Slack provisioning, manifests, tokens, doctor, engagement rules, access policy, and approval buttons.","frontmatter":{"title":"Slack","description":"Put the agent in Slack over Socket Mode: Add to Slack provisioning, manifests, tokens, doctor, engagement rules, access policy, and approval buttons."},"headers":[],"relativePath":"guides/slack.md","filePath":"guides/slack.md"}'),n={name:"guides/slack.md"};function h(l,s,o,p,r,d){return i(),e("div",null,[...s[0]||(s[0]=[t(`<h1 id="slack-agents" tabindex="-1">Slack agents <a class="header-anchor" href="#slack-agents" aria-label="Permalink to "Slack agents""></a></h1><p>The Slack channel puts your agent in Slack over Socket Mode: no public Request URL, streaming replies in threads, tool "thinking" steps, suggested prompts, and opt-in approval buttons. Cursor's <strong>Add to Slack</strong> provisioning handles the setup in one CLI command or one dashboard click; the manual manifest flow remains as a fallback.</p><p>The companion skill is <a href="./../../skills/setup-slack/SKILL.html"><code>skills/setup-slack/SKILL.md</code></a>.</p><h2 id="define-the-channel" tabindex="-1">Define the channel <a class="header-anchor" href="#define-the-channel" aria-label="Permalink to "Define the channel""></a></h2><p>Author <code>agent/channels/slack.ts</code> with <code>slackChannel()</code> from <code>@cursor/july/channels/slack</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { slackChannel } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "@cursor/july/channels/slack"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
|
2
|
+
<span class="line"></span>
|
|
3
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// Single agent: reads SLACK_BOT_TOKEN + SLACK_APP_TOKEN</span></span>
|
|
4
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">();</span></span>
|
|
5
|
+
<span class="line"></span>
|
|
6
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// Multi-agent serve: one Slack app (and token pair) per agent</span></span>
|
|
7
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ envPrefix: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"WEATHER_AGENT"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
|
|
8
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// → WEATHER_AGENT_SLACK_BOT_TOKEN + WEATHER_AGENT_SLACK_APP_TOKEN</span></span></code></pre></div><p>By default the channel connects over Socket Mode (the app connects outward, so it works from behind any firewall) and responds only to <code>app_mention</code> events and direct messages. It also refuses Slack Connect users, guests, and senders from other workspaces. Threads bind to sessions with <code>continuationToken = channelId:threadTs</code>, so a thread is one durable conversation. Replies stream (<code>chat.startStream</code> / <code>appendStream</code> / <code>stopStream</code>) with a plain-message fallback, a rotating status shows while the agent works, and the pack sets thread titles and suggested prompts. When a Slack API is unavailable (<code>method_not_found</code>, <code>missing_scope</code>), the pack degrades to <code>postMessage</code> instead of failing.</p><p>Missing tokens leave the channel idle (<code>channel idle … missing credentials</code>) rather than failing <code>serve</code>. That's useful when you mount many agents and only some have Slack apps.</p><h2 id="use-the-cursor-slack-connection" tabindex="-1">Use the Cursor Slack connection <a class="header-anchor" href="#use-the-cursor-slack-connection" aria-label="Permalink to "Use the Cursor Slack connection""></a></h2><p>If the Cursor Slack app is already installed in your workspace and linked to your Cursor account, skip the dedicated Slack app:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { slackChannel } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "@cursor/july/channels/slack"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
|
9
|
+
<span class="line"></span>
|
|
10
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
11
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> cursorAccount: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
12
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> agentName: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"Weatherbot"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// single token — no spaces; defaults from mount slug (PascalCase)</span></span>
|
|
13
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> agentIcon: { emoji: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">":robot_face:"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
14
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Sign the host in (<code>agent-sdk login</code> or <code>CURSOR_API_KEY</code>), then mention the agent in Slack as <code>@Cursor Weatherbot …</code>. Thread replies and DMs keep going to the same agent. Messages appear as the Cursor app under that agent's name and icon, with live updates as the turn progresses.</p><p>Use a dedicated Socket Mode Slack app when you need your own bot user, channel watching (<code>engagement.channelPosts</code>), or approval buttons. On <code>cursorAccount</code>, agents must be explicitly addressed (@mention, DM, or claimed-thread reply). Channel watching and <code>toolApprovals</code> / <code>interactivity</code> are Socket Mode only; the Cursor connection does not relay Block Kit clicks. Agent names must be unique on the host; an unmatched <code>@Cursor <name></code> stays on Cursor's normal Slack agent.</p><h2 id="control-who-can-message-the-agent" tabindex="-1">Control who can message the agent <a class="header-anchor" href="#control-who-can-message-the-agent" aria-label="Permalink to "Control who can message the agent""></a></h2><p>External senders are blocked by default. Slack Connect users, guests, and people whose home workspace is not the install team never reach the handler. That applies to Socket Mode and <code>cursorAccount: true</code>. Set <code>blockExternals: false</code> only when the agent should serve people outside your org:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
15
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> policy: { blockExternals: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
16
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Sessions are thread-scoped by default, so anyone in the thread can continue. Restrict follow-ups to the person who started the session with <code>respondTo: "author"</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
17
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> policy: { respondTo: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"author"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
18
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><h2 id="set-it-up" tabindex="-1">Set it up <a class="header-anchor" href="#set-it-up" aria-label="Permalink to "Set it up""></a></h2><p>Start with Cursor's <strong>Add to Slack</strong> provisioning: Cursor creates and installs a dedicated Slack app for the agent and delivers its tokens, so nobody visits <a href="https://api.slack.com/apps" target="_blank" rel="noreferrer">api.slack.com</a> or copies an <code>xoxb-…</code> / <code>xapp-…</code> pair by hand. Use the CLI for local development and the dashboard for hosted deployments. Fall back to the <a href="#manual-setup-fallback">manual manifest flow</a> only when provisioning reports the feature is not enabled for your account.</p><h3 id="provision-with-the-cli" tabindex="-1">Provision with the CLI <a class="header-anchor" href="#provision-with-the-cli" aria-label="Permalink to "Provision with the CLI""></a></h3><p>One command runs the whole setup:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> create</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # dev app (default)</span></span>
|
|
19
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> create</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --prod</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # prod app</span></span></code></pre></div><p><code>slack create</code> needs a signed-in host (<code>agent-sdk login</code> or <code>CURSOR_API_KEY</code>). It scaffolds <code>agent/channels/slack.ts</code> when the file is missing, connects your Slack workspace through a browser consent page when it isn't connected yet (a one-time authorization per user and workspace), creates and installs the agent's dedicated Socket Mode app, writes <code><PREFIX>_SLACK_BOT_TOKEN</code> and <code><PREFIX>_SLACK_APP_TOKEN</code> into <code><dir>/.env.local</code>, and finishes with a <code>doctor</code> pass. Then serve and smoke it as described <a href="#wire-the-env-and-verify">below</a>; the tokens are already in place.</p><p>If the workspace requires admin approval for new apps, <code>create</code> prints the Slack approval page for a workspace admin. Re-run <code>agent-sdk slack create</code> after the approval to finish the install and mint the tokens.</p><p>Useful companions: <code>--slack-team T0123ABCD</code> picks a workspace when several are connected, <code>--icon <https-url-or-file></code> sets the app icon, <code>agent-sdk slack destroy</code> deletes the provisioned app, and <code>agent-sdk slack icon <source></code> updates the icon later. A re-run of <code>create</code> refuses to overwrite manifest edits made by hand in Slack; pass <code>--force</code> to overwrite them.</p><h3 id="provision-from-the-dashboard-hosted-deployments" tabindex="-1">Provision from the dashboard (hosted deployments) <a class="header-anchor" href="#provision-from-the-dashboard-hosted-deployments" aria-label="Permalink to "Provision from the dashboard (hosted deployments)""></a></h3><p>For a <a href="./../deployment.html#cursor-managed-hosting">Cursor-hosted deployment</a>, provision from <a href="https://cursor.com/dashboard" target="_blank" rel="noreferrer">cursor.com/dashboard</a>: open <strong>Deployed Agents</strong>, select the deployment, switch to the <strong>Details</strong> view, and expand the <strong>Slack</strong> row under <strong>Integrations</strong>.</p><ol><li>Click <strong>Add to Slack</strong> and approve the authorization in the tab that opens. This is a one-time consent per user and workspace.</li><li>Pick the bot name (and the workspace, when several are connected) and click <strong>Create Slack app</strong>. Cursor creates and installs the app, then stores its tokens as deployment secrets; the values are never shown. The <strong>Advanced</strong> disclosure sets the env-var prefix, so the secret names match what your <code>slackChannel({ envPrefix })</code> reads.</li><li>If the workspace requires admin approval, the row shows <strong>Waiting for admin approval</strong> with an <strong>Approve in Slack</strong> button that opens Slack's pending-request page. After an admin approves, pick <strong>Retry</strong> from the row's menu.</li><li>Click <strong>Redeploy</strong> when the banner appears. The running agent keeps its old environment until the next deploy.</li></ol><p>The row's menu also covers later care: rename the app, set its icon, rotate its tokens, remove it from Slack, or disconnect the workspace.</p><h3 id="manual-setup-fallback" tabindex="-1">Manual setup (fallback) <a class="header-anchor" href="#manual-setup-fallback" aria-label="Permalink to "Manual setup (fallback)""></a></h3><p>When Add to Slack is not enabled for your account, create the apps by hand. Generate the channel file, the app manifests, and the env template:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> init</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --name</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "My Agent"</span></span></code></pre></div><p>This writes <code>agent/channels/slack.ts</code> (with an <code>envPrefix</code> derived from the directory name), importable app manifests at <code>.agent-serve/slack/manifest.{dev,prod}.json</code>, and <code>.agent-serve/slack/env.example</code>. Use <code>--no-prefix</code> for the shared <code>SLACK_*</code> variables on single-agent hosts, <code>--prefix CUSTOM</code> to override, and <code>--channel-posts</code> if you plan to watch channels.</p><h4 id="create-the-apps-human-slack-admin" tabindex="-1">Create the apps (human, Slack admin) <a class="header-anchor" href="#create-the-apps-human-slack-admin" aria-label="Permalink to "Create the apps (human, Slack admin)""></a></h4><p>This phase needs a human with permission to create Slack apps.</p><ol><li>Open <a href="https://api.slack.com/apps" target="_blank" rel="noreferrer">api.slack.com/apps</a> → <strong>Create New App</strong> → <strong>From a manifest</strong>.</li><li>Paste <code>manifest.dev.json</code> and create the dev app.</li><li>Repeat with <code>manifest.prod.json</code>. Dev and prod are separate Slack apps with separate tokens.</li></ol><h4 id="install-and-mint-tokens-human" tabindex="-1">Install and mint tokens (human) <a class="header-anchor" href="#install-and-mint-tokens-human" aria-label="Permalink to "Install and mint tokens (human)""></a></h4><p>For each app: <strong>Install to Workspace</strong> and copy the Bot User OAuth Token (<code>xoxb-…</code>), then under <strong>Basic Information → App-Level Tokens</strong> create a token with scope <code>connections:write</code> and copy it (<code>xapp-…</code>).</p><h3 id="wire-the-env-and-verify" tabindex="-1">Wire the env and verify <a class="header-anchor" href="#wire-the-env-and-verify" aria-label="Permalink to "Wire the env and verify""></a></h3><p><code>agent-sdk slack create</code> already wrote the tokens to <code>.env.local</code>, so after provisioning skip straight to <code>doctor</code>. After a manual setup, export the tokens in the shell that runs <code>serve</code>, using the names from <code>env.example</code>, or put them in the agent directory's <code>.env.local</code> — <code>serve</code>/<code>dev</code>/<code>slack doctor</code> load that file (real environment variables always win over it):</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MY_AGENT_SLACK_BOT_TOKEN</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">xoxb-…</span></span>
|
|
20
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MY_AGENT_SLACK_APP_TOKEN</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">xapp-…</span></span></code></pre></div><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> doctor</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --prefix</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> MY_AGENT</span></span></code></pre></div><p>Proceed when <code>app_token</code>, <code>connections_open</code>, <code>bot_token</code>, and <code>auth_test</code> are all green. Then serve and smoke it:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> serve</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dev</span></span>
|
|
21
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># expect: [agent-sdk/slack] Socket Mode connected</span></span></code></pre></div><p>Invite the bot to a channel and @mention it (or DM it). Expect the Thinking… status, then a threaded streaming reply, with correlated server logs (<code>inbound kind=app_mention</code>, <code>session start</code>, <code>reply delivered via stream|postMessage</code>).</p><h2 id="choose-when-the-agent-engages" tabindex="-1">Choose when the agent engages <a class="header-anchor" href="#choose-when-the-agent-engages" aria-label="Permalink to "Choose when the agent engages""></a></h2><p>Mentions and DMs are on by default. Watching channels means dispatching on new posts without a mention. That's an explicit opt-in:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
22
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> envPrefix: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"TRIAGE"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
23
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> engagement: {</span></span>
|
|
24
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // mentions / directMessages default to true</span></span>
|
|
25
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> channelPosts: {</span></span>
|
|
26
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> allow: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"#triage-alerts"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">], </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// explicit allowlist; no wildcard exists</span></span>
|
|
27
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> posts: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"top-level"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// default: thread replies never dispatch</span></span>
|
|
28
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> debounceMs: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">15_000</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// optional: let rapid edits settle</span></span>
|
|
29
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> includeBotPosts: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// default: bot-authored posts never dispatch</span></span>
|
|
30
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
31
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
32
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onChannelPost</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">ctx</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">message</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
|
33
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // same contract as onAppMention: return null to skip</span></span>
|
|
34
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> message.markdown.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">length</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ></span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 20</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {} </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
|
35
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
36
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Channel watching needs the <code>message.channels</code> / <code>message.groups</code> events on the Slack app (Socket Mode only — not available with <code>cursorAccount: true</code>). Generate manifests with <code>slack init --channel-posts</code>, or add the events and re-import. The bot must also be a member of each watched channel. Posts that mention the bot stay on the <code>app_mention</code> path, bot-authored posts never dispatch by default, and deleting a post inside the debounce window cancels its dispatch. Watched posts reuse the thread-scoped principal, so a later @mention continues the same session. Set <code>engagement.mentions</code> or <code>engagement.directMessages</code> to <code>false</code> to turn those surfaces off.</p><p>Set <code>includeBotPosts: true</code> when the posts worth watching come from bots: alert feeds, webhook integrations, or other agents posting notes. The watching app's own posts stay dropped either way, matched by the <code>bot_id</code> and bot user id from <code>auth.test</code>, so an agent can never dispatch on its own replies. The <a href="./../example-agents/oncall.html">alert investigator example</a> watches a bot-fed alerts channel this way.</p><h2 id="prepare-work-on-the-host" tabindex="-1">Prepare work on the host <a class="header-anchor" href="#prepare-work-on-the-host" aria-label="Permalink to "Prepare work on the host""></a></h2><p>Mention and DM handlers may return a prepared <code>message</code>, <code>workspaceFiles</code>, or <code>cloud</code> block. It's the same host-prep pattern as <a href="./webhooks.html#prepare-on-the-host-then-hand-off">custom channels</a>. PR agents use it: extract a PR URL from the mention text and run the same host path as the HTTP channel.</p><h2 id="add-approval-buttons" tabindex="-1">Add approval buttons <a class="header-anchor" href="#add-approval-buttons" aria-label="Permalink to "Add approval buttons""></a></h2><p>Tools with <code>needsApproval</code> park until a person decides. Route that through Slack with one flag:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
37
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> toolApprovals: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// posts Block Kit Approve/Deny cards + routes clicks</span></span>
|
|
38
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>The Slack app manifest must have interactivity enabled. Regenerate with <code>buildSlackManifest({ interactivity: true })</code> (or edit and re-import) if your app predates it. Composing events by hand instead: spread <code>buildToolApprovalEvents({ credentials })</code> into <code>events</code> and set <code>interactivity: true</code> on the channel so Socket Mode routes the clicks.</p><p>Approval buttons need Socket Mode. <code>slackChannel({ cursorAccount: true })</code> rejects <code>toolApprovals</code> and <code>interactivity</code> at construction, since the Cursor Slack connection does not relay Block Kit clicks. Use a dedicated Slack app to run approvals for a cursor-account agent.</p><p>Cards show redacted, truncated arguments (Block Kit size limits); execution still uses the full validated input, so review sensitive tools in the playground when the arguments may exceed the card. Approvals exist for <code>execution: "server"</code> tools on the local runtime only, and parked calls do not survive a host restart. The full lifecycle is in <a href="./human-in-the-loop.html">Human-in-the-loop</a>.</p><h2 id="run-several-agents-on-one-host" tabindex="-1">Run several agents on one host <a class="header-anchor" href="#run-several-agents-on-one-host" aria-label="Permalink to "Run several agents on one host""></a></h2><p>One Slack app and token pair per agent. Never share a pair across agents in the same process. <code>envPrefix</code> keeps them apart (<code>WEATHER_AGENT_SLACK_*</code>, <code>TRIAGE_SLACK_*</code>, …), and agents without tokens mount with their Slack channel idle while everything else serves normally.</p><h2 id="keep-the-channel-healthy" tabindex="-1">Keep the channel healthy <a class="header-anchor" href="#keep-the-channel-healthy" aria-label="Permalink to "Keep the channel healthy""></a></h2><p>Two habits matter most.</p><ul><li>Don't <code>await</code> long work inside Slack dispatch handlers. The pack dispatches through <code>waitUntil</code> and streams as the turn progresses.</li><li>In <code>--dev</code> (loopback) or <code>--allow-anonymous</code> (trusted shared host), the playground can list and stream Slack sessions and resolve their parked approvals (the audit trail records the HTTP caller). Bearer-auth hosts stay strict: Slack approvals must come from Slack interactivity or a matching principal.</li></ul><h2 id="cli-reference" tabindex="-1">CLI reference <a class="header-anchor" href="#cli-reference" aria-label="Permalink to "CLI reference""></a></h2><p>The <code>slack</code> subcommands cover setup end to end.</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> setup</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # guided checklist</span></span>
|
|
39
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> create</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # provision via Add to Slack (dev app)</span></span>
|
|
40
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> create</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --prod</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # prod app</span></span>
|
|
41
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> destroy</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # delete the provisioned app</span></span>
|
|
42
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> icon</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ./icon.png</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # set the provisioned app's icon</span></span>
|
|
43
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> init</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --name</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "My Agent"</span></span>
|
|
44
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> init</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --no-prefix</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # shared SLACK_* vars</span></span>
|
|
45
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> init</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --channel-posts</span></span>
|
|
46
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> manifest</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --env</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> both</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # regenerate manifests</span></span>
|
|
47
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> doctor</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --prefix</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> MY_AGENT</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # token / connectivity checks</span></span></code></pre></div><h2 id="what-s-next" tabindex="-1">What's next <a class="header-anchor" href="#what-s-next" aria-label="Permalink to "What's next""></a></h2><p>Continue with these pages:</p><ul><li><a href="./human-in-the-loop.html">Human-in-the-loop</a>: the approval lifecycle behind <code>toolApprovals</code></li><li><a href="./webhooks.html">Webhooks and custom channels</a>: the mechanism this pack is built on</li></ul>`,70)])])}const g=a(n,[["render",h]]);export{c as __pageData,g as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const c=JSON.parse('{"title":"Slack","description":"Put the agent in Slack over Socket Mode: Add to Slack provisioning, manifests, tokens, doctor, engagement rules, access policy, and approval buttons.","frontmatter":{"title":"Slack","description":"Put the agent in Slack over Socket Mode: Add to Slack provisioning, manifests, tokens, doctor, engagement rules, access policy, and approval buttons."},"headers":[],"relativePath":"guides/slack.md","filePath":"guides/slack.md"}'),n={name:"guides/slack.md"};function h(l,s,o,p,r,d){return i(),e("div",null,[...s[0]||(s[0]=[t("",70)])])}const g=a(n,[["render",h]]);export{c as __pageData,g as default};
|
|
@@ -180,4 +180,4 @@ import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.CAZyNGu9.js";const o
|
|
|
180
180
|
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .update(fs.readFileSync("fixtures/issue-create.json")).digest("hex"))'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
|
|
181
181
|
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">curl</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -X</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> POST</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> http://127.0.0.1:3000/</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"><</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">slu</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">g</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">></span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">/v1/channels/linear/</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> \\</span></span>
|
|
182
182
|
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -H</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'content-type: application/json'</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -H</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "linear-signature: </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">$SIG</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> \\</span></span>
|
|
183
|
-
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --data-binary</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @fixtures/issue-create.json</span></span></code></pre></div><h2 id="test-a-channel" tabindex="-1">Test a channel <a class="header-anchor" href="#test-a-channel" aria-label="Permalink to "Test a channel""></a></h2><p>Start with curl and saved payloads under <code>fixtures/</code>. The playground's <strong>Try</strong> modal covers manual probes. It remembers your last body per endpoint, has Copy curl, and opens the created session on a successful Try. For regression coverage, drive the same behavior through an eval, or keep channel logic deterministic in <code>agent/lib/</code> and unit-test it there. When something looks wrong, read the session's <code>events.ndjson</code>. The stream is the record of what happened.</p><p>For GitHub specifically, don't hand-roll fixtures. <code>
|
|
183
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --data-binary</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @fixtures/issue-create.json</span></span></code></pre></div><h2 id="test-a-channel" tabindex="-1">Test a channel <a class="header-anchor" href="#test-a-channel" aria-label="Permalink to "Test a channel""></a></h2><p>Start with curl and saved payloads under <code>fixtures/</code>. The playground's <strong>Try</strong> modal covers manual probes. It remembers your last body per endpoint, has Copy curl, and opens the created session on a successful Try. For regression coverage, drive the same behavior through an eval, or keep channel logic deterministic in <code>agent/lib/</code> and unit-test it there. When something looks wrong, read the session's <code>events.ndjson</code>. The stream is the record of what happened.</p><p>For GitHub specifically, don't hand-roll fixtures. <code>agent-sdk github replay</code> synthesizes real-shaped, signed payloads from any PR you can read. See the <a href="./github.html">GitHub guide</a>.</p><h2 id="what-s-next" tabindex="-1">What's next <a class="header-anchor" href="#what-s-next" aria-label="Permalink to "What's next""></a></h2><p>Continue with these pages:</p><ul><li><a href="./../reference/channels.html">Channels reference</a>: the full authoring API</li><li><a href="./github.html">GitHub</a> and <a href="./slack.html">Slack</a>: the packaged channels</li><li><a href="./../reference/sessions.html">Sessions and streaming</a>: events your channel can subscribe to</li></ul>`,49)])])}const g=i(t,[["render",e]]);export{o as __pageData,g as default};
|