@cursor/july 0.1.35 → 0.1.36
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 +5 -9
- package/README.md +5 -9
- package/dist/channels/github/github-channel.d.ts +1 -1
- package/dist/channels/github/github-channel.js +1 -1
- package/dist/channels/github/index.d.ts +1 -1
- package/dist/channels/github/index.js +1 -1
- package/dist/channels/slack/index.d.ts +1 -1
- package/dist/channels/slack/index.js +1 -1
- package/dist/channels/slack/init.d.ts.map +1 -1
- package/dist/channels/slack/init.js +2 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +8 -17
- package/dist/docs/assets/{ab.md.DAQoJ-up.js → ab.md.6cLOW7--.js} +4 -13
- package/dist/docs/assets/{ab.md.DAQoJ-up.lean.js → ab.md.6cLOW7--.lean.js} +1 -1
- package/dist/docs/assets/{app.D5Mv1T0U.js → app.DEcxy4oz.js} +1 -1
- package/dist/docs/assets/{building-with-agents.md.CnHqvYDd.js → building-with-agents.md.txrcGU2B.js} +2 -2
- package/dist/docs/assets/chunks/@localSearchIndexroot.ByFYcFly.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.CMq_BQce.js → VPLocalSearchBox.n1VOZcy3.js} +1 -1
- package/dist/docs/assets/chunks/{theme.C6D9UPLK.js → theme.BaF1MQ9c.js} +2 -2
- package/dist/docs/assets/{concepts.md.DFaQEFkA.js → concepts.md.CqOsxbMU.js} +1 -1
- package/dist/docs/assets/{deployment.md.9MYBuKM1.js → deployment.md.CuK5SNjN.js} +1 -1
- package/dist/docs/assets/{evals.md.BIUoVZ6X.js → evals.md.BQXI3rXy.js} +9 -15
- package/dist/docs/assets/{evals.md.BIUoVZ6X.lean.js → evals.md.BQXI3rXy.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_approval-buddy.md.BhEfleVx.js → example-agents_approval-buddy.md.CIiZ9coo.js} +1 -1
- package/dist/docs/assets/{example-agents_benny.md.2Et1qa8f.js → example-agents_benny.md.l7JTmm8X.js} +1 -1
- package/dist/docs/assets/{example-agents_bugbot.md.ByUexi5i.js → example-agents_bugbot.md.Dp5JqHSQ.js} +2 -2
- package/dist/docs/assets/{example-agents_bugbot.md.ByUexi5i.lean.js → example-agents_bugbot.md.Dp5JqHSQ.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_codebase-wiki.md.B4y-7ZVW.js → example-agents_codebase-wiki.md.D-lteFf0.js} +1 -1
- package/dist/docs/assets/{example-agents_codebase-wiki.md.B4y-7ZVW.lean.js → example-agents_codebase-wiki.md.D-lteFf0.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_codeowners-review.md.D6ay4nvf.js → example-agents_codeowners-review.md.BU2ZXLf-.js} +1 -1
- package/dist/docs/assets/{example-agents_codeowners-review.md.D6ay4nvf.lean.js → example-agents_codeowners-review.md.BU2ZXLf-.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_concierge.md.lL8rhYlj.js → example-agents_concierge.md.DA2al_NK.js} +2 -2
- package/dist/docs/assets/{example-agents_concierge.md.lL8rhYlj.lean.js → example-agents_concierge.md.DA2al_NK.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_fsd.md.DfNKQTHz.js → example-agents_fsd.md.DPz9ezO4.js} +1 -1
- package/dist/docs/assets/{example-agents_knowledge-base.md.CzyZ2DCr.js → example-agents_knowledge-base.md.IneynQSR.js} +1 -1
- package/dist/docs/assets/{example-agents_oncall.md.wFFXXEyW.js → example-agents_oncall.md.ZE0n6ZFN.js} +1 -1
- package/dist/docs/assets/{example-agents_slack-agent.md.DvgvT4nn.js → example-agents_slack-agent.md.06jQXTAI.js} +1 -1
- package/dist/docs/assets/{example-agents_weather-agent.md.BADkPqxQ.js → example-agents_weather-agent.md.CrGZ0SqR.js} +3 -3
- package/dist/docs/assets/{example-agents_weather-agent.md.BADkPqxQ.lean.js → example-agents_weather-agent.md.CrGZ0SqR.lean.js} +1 -1
- package/dist/docs/assets/guides_cloud-runtime.md.V5igN4Sq.js +9 -0
- package/dist/docs/assets/guides_cloud-runtime.md.V5igN4Sq.lean.js +1 -0
- package/dist/docs/assets/{guides_webhooks.md.DiAwSR42.js → guides_webhooks.md.BERuBSJW.js} +1 -1
- package/dist/docs/assets/{hillclimbing.md.D9Y1_bYh.js → hillclimbing.md.yXqdlv2R.js} +1 -1
- package/dist/docs/assets/index.md.CmhptOmN.js +24 -0
- package/dist/docs/assets/{index.md.CZqbBJPB.lean.js → index.md.CmhptOmN.lean.js} +1 -1
- package/dist/docs/assets/{quickstart.md.TnEXYgYW.js → quickstart.md.C_b6ESpD.js} +7 -4
- package/dist/docs/assets/{quickstart.md.TnEXYgYW.lean.js → quickstart.md.C_b6ESpD.lean.js} +1 -1
- package/dist/docs/assets/{reference_agent-config.md.kuN6-OxK.js → reference_agent-config.md.CRmkoxd6.js} +6 -4
- package/dist/docs/assets/{reference_agent-config.md.kuN6-OxK.lean.js → reference_agent-config.md.CRmkoxd6.lean.js} +1 -1
- package/dist/docs/assets/reference_artifacts.md.BGG4bZo-.js +19 -0
- package/dist/docs/assets/reference_artifacts.md.BGG4bZo-.lean.js +1 -0
- package/dist/docs/assets/{reference_channels.md.CDhTRfUz.js → reference_channels.md.BIabFUAI.js} +2 -2
- package/dist/docs/assets/{reference_channels.md.CDhTRfUz.lean.js → reference_channels.md.BIabFUAI.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.sD-IUWjg.js → reference_cli.md.Byvrg8eu.js} +15 -9
- package/dist/docs/assets/{reference_cli.md.sD-IUWjg.lean.js → reference_cli.md.Byvrg8eu.lean.js} +1 -1
- package/dist/docs/assets/{reference_hooks.md.DyLVfE1O.js → reference_hooks.md.BGDw4VLm.js} +2 -2
- package/dist/docs/assets/{reference_hooks.md.DyLVfE1O.lean.js → reference_hooks.md.BGDw4VLm.lean.js} +1 -1
- package/dist/docs/assets/reference_http-api.md.DGrw_wOu.js +11 -0
- package/dist/docs/assets/reference_http-api.md.DGrw_wOu.lean.js +1 -0
- package/dist/docs/assets/{reference_project-layout.md.D8E6ZmHJ.js → reference_project-layout.md._XdeMahr.js} +2 -2
- package/dist/docs/assets/{reference_project-layout.md.D8E6ZmHJ.lean.js → reference_project-layout.md._XdeMahr.lean.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.C_ouF_uf.js → reference_sessions.md.DBVFi2Sx.js} +2 -2
- package/dist/docs/assets/{reference_subagents.md.zWAMNfi1.js → reference_subagents.md.DSrGLIuB.js} +2 -2
- package/dist/docs/assets/{reference_subagents.md.zWAMNfi1.lean.js → reference_subagents.md.DSrGLIuB.lean.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.BswAQM41.js → reference_tools.md.lSrsTxYJ.js} +4 -4
- package/dist/docs/assets/{reference_tools.md.BswAQM41.lean.js → reference_tools.md.lSrsTxYJ.lean.js} +1 -1
- package/dist/docs/assets/scaffolding-agents.md.mkc3B_ZW.js +1 -0
- package/dist/docs/assets/{scaffolding-agents.md.Bsr9Pwzu.lean.js → scaffolding-agents.md.mkc3B_ZW.lean.js} +1 -1
- package/dist/docs/assets/{storage.md.xZoiGM58.js → storage.md.mQDtIULc.js} +3 -3
- package/dist/docs/assets/{storage.md.xZoiGM58.lean.js → storage.md.mQDtIULc.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +6 -6
- package/dist/docs/concepts.html +5 -5
- package/dist/docs/deployment.html +6 -6
- package/dist/docs/evals.html +13 -19
- package/dist/docs/example-agents/approval-buddy.html +5 -5
- package/dist/docs/example-agents/benny.html +5 -5
- package/dist/docs/example-agents/bugbot.html +5 -5
- package/dist/docs/example-agents/codebase-wiki.html +5 -5
- package/dist/docs/example-agents/codeowners-review.html +5 -5
- package/dist/docs/example-agents/concierge.html +6 -6
- package/dist/docs/example-agents/fsd.html +5 -5
- package/dist/docs/example-agents/index.html +4 -4
- package/dist/docs/example-agents/knowledge-base.html +5 -5
- package/dist/docs/example-agents/oncall.html +5 -5
- package/dist/docs/example-agents/security-reviewer.html +4 -4
- package/dist/docs/example-agents/slack-agent.html +5 -5
- package/dist/docs/example-agents/weather-agent.html +6 -6
- package/dist/docs/guides/agent-to-agent.html +5 -5
- package/dist/docs/guides/cloud-runtime.html +6 -6
- package/dist/docs/guides/github.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +5 -5
- package/dist/docs/guides/slack.html +4 -4
- package/dist/docs/guides/webhooks.html +6 -6
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +6 -6
- package/dist/docs/index.html +11 -7
- package/dist/docs/quickstart.html +10 -7
- package/dist/docs/reference/agent-config.html +10 -8
- package/dist/docs/reference/artifacts.html +43 -0
- package/dist/docs/reference/channels.html +6 -6
- package/dist/docs/reference/cli.html +18 -12
- package/dist/docs/reference/connections.html +4 -4
- package/dist/docs/reference/hooks.html +6 -6
- package/dist/docs/reference/http-api.html +7 -7
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +6 -6
- package/dist/docs/reference/prompt.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +7 -7
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +6 -6
- package/dist/docs/reference/tools.html +7 -7
- package/dist/docs/scaffolding-agents.html +5 -5
- package/dist/docs/storage.html +6 -6
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/files-backends/agent-store-presigned-url.d.ts.map +1 -1
- package/dist/files-backends/agent-store-presigned-url.js +15 -22
- package/dist/internal/cli-github.d.ts.map +1 -1
- package/dist/internal/cli-github.js +8 -7
- package/dist/internal/cli-slack.js +9 -9
- package/dist/internal/event-mapper.d.ts +3 -3
- package/dist/internal/event-mapper.d.ts.map +1 -1
- package/dist/internal/event-mapper.js +7 -4
- package/dist/internal/session-engine.js +3 -3
- package/dist/internal/workspace.d.ts +8 -6
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +15 -11
- package/dist/playground/assets/{index-D7OV8B_H.js → index-DOnKC85G.js} +18 -18
- package/dist/playground/assets/{index-DOb96C0M.css → index-DoQjqj5w.css} +1 -1
- package/dist/playground/index.html +2 -2
- package/docs/README.md +32 -13
- package/docs/ab.md +23 -36
- package/docs/building-with-agents.md +2 -2
- package/docs/concepts.md +3 -2
- package/docs/deployment.md +1 -1
- package/docs/evals.md +102 -33
- package/docs/example-agents/approval-buddy.md +2 -1
- package/docs/example-agents/benny.md +2 -0
- package/docs/example-agents/bugbot.md +3 -0
- package/docs/example-agents/codebase-wiki.md +2 -0
- package/docs/example-agents/codeowners-review.md +2 -0
- package/docs/example-agents/concierge.md +1 -0
- package/docs/example-agents/fsd.md +1 -0
- package/docs/example-agents/knowledge-base.md +2 -0
- package/docs/example-agents/oncall.md +2 -0
- package/docs/example-agents/slack-agent.md +1 -0
- package/docs/example-agents/weather-agent.md +9 -4
- package/docs/guides/cloud-runtime.md +11 -4
- package/docs/guides/webhooks.md +1 -1
- package/docs/hillclimbing.md +1 -1
- package/docs/quickstart.md +39 -7
- package/docs/reference/agent-config.md +74 -14
- package/docs/reference/artifacts.md +117 -0
- package/docs/reference/channels.md +45 -15
- package/docs/reference/cli.md +141 -20
- package/docs/reference/hooks.md +11 -4
- package/docs/reference/http-api.md +50 -4
- package/docs/reference/project-layout.md +6 -0
- package/docs/reference/sessions.md +5 -4
- package/docs/reference/subagents.md +5 -3
- package/docs/reference/tools.md +23 -7
- package/docs/scaffolding-agents.md +11 -2
- package/docs/storage.md +27 -2
- package/package.json +1 -1
- package/src/channels/github/github-channel.ts +1 -1
- package/src/channels/github/index.ts +1 -1
- package/src/channels/slack/index.ts +1 -1
- package/src/channels/slack/init.ts +2 -1
- package/src/files-backends/agent-store-presigned-url.ts +2 -1
- package/src/internal/cli-github.ts +8 -7
- package/src/internal/cli-slack.ts +9 -9
- package/src/internal/event-mapper.ts +9 -4
- package/src/internal/session-engine.ts +3 -3
- package/src/internal/workspace.ts +15 -11
- package/dist/docs/assets/chunks/@localSearchIndexroot.Cu7b6o1D.js +0 -1
- package/dist/docs/assets/guides_cloud-runtime.md.CDJGvVC4.js +0 -9
- package/dist/docs/assets/guides_cloud-runtime.md.CDJGvVC4.lean.js +0 -1
- package/dist/docs/assets/index.md.CZqbBJPB.js +0 -20
- package/dist/docs/assets/reference_http-api.md.CfVM_ICa.js +0 -11
- package/dist/docs/assets/reference_http-api.md.CfVM_ICa.lean.js +0 -1
- package/dist/docs/assets/scaffolding-agents.md.Bsr9Pwzu.js +0 -1
- /package/dist/docs/assets/{building-with-agents.md.CnHqvYDd.lean.js → building-with-agents.md.txrcGU2B.lean.js} +0 -0
- /package/dist/docs/assets/{concepts.md.DFaQEFkA.lean.js → concepts.md.CqOsxbMU.lean.js} +0 -0
- /package/dist/docs/assets/{deployment.md.9MYBuKM1.lean.js → deployment.md.CuK5SNjN.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_approval-buddy.md.BhEfleVx.lean.js → example-agents_approval-buddy.md.CIiZ9coo.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_benny.md.2Et1qa8f.lean.js → example-agents_benny.md.l7JTmm8X.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_fsd.md.DfNKQTHz.lean.js → example-agents_fsd.md.DPz9ezO4.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_knowledge-base.md.CzyZ2DCr.lean.js → example-agents_knowledge-base.md.IneynQSR.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_oncall.md.wFFXXEyW.lean.js → example-agents_oncall.md.ZE0n6ZFN.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_slack-agent.md.DvgvT4nn.lean.js → example-agents_slack-agent.md.06jQXTAI.lean.js} +0 -0
- /package/dist/docs/assets/{guides_webhooks.md.DiAwSR42.lean.js → guides_webhooks.md.BERuBSJW.lean.js} +0 -0
- /package/dist/docs/assets/{hillclimbing.md.D9Y1_bYh.lean.js → hillclimbing.md.yXqdlv2R.lean.js} +0 -0
- /package/dist/docs/assets/{reference_sessions.md.C_ouF_uf.lean.js → reference_sessions.md.DBVFi2Sx.lean.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import{_ as t,c as i,o as a,ag as l}from"./chunks/framework.CAZyNGu9.js";const m=JSON.parse('{"title":"Hillclimbing","description":"Improve an agent one measured round at a time, with the hillclimb skill running the loop with you.","frontmatter":{"title":"Hillclimbing","description":"Improve an agent one measured round at a time, with the hillclimb skill running the loop with you."},"headers":[],"relativePath":"hillclimbing.md","filePath":"hillclimbing.md"}'),o={name:"hillclimbing.md"};function n(r,e,s,h,d,c){return a(),i("div",null,[...e[0]||(e[0]=[l(`<h1 id="hillclimbing" tabindex="-1">Hillclimbing <a class="header-anchor" href="#hillclimbing" aria-label="Permalink to "Hillclimbing""></a></h1><p>Make an agent better on fixed inputs: measure, change one lever, remeasure, and lock every kept win with an eval.</p><h2 id="what-is-hillclimbing" tabindex="-1">What is hillclimbing? <a class="header-anchor" href="#what-is-hillclimbing" aria-label="Permalink to "What is hillclimbing?""></a></h2><p>Hillclimbing is a measured improvement loop. You pin a few fixtures, name the one dominant problem in the run, change one lever, and check the same fixtures again. Keep only what helps. Every kept change lands an <a href="./evals.html">eval</a> so the win stays put.</p><p>You don't have to run the loop alone. The package ships a coding-agent skill that drives it with you.</p><div class="language-mermaid vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">mermaid</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">flowchart LR</span></span>
|
|
2
2
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> measure[Measure] --> change[Change one lever]</span></span>
|
|
3
3
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> change --> remeasure[Remeasure]</span></span>
|
|
4
|
-
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> remeasure --> measure</span></span></code></pre></div><h2 id="how-do-i-hillclimb-an-agent-with-a-coding-agent" tabindex="-1">How do I hillclimb an agent with a coding agent? <a class="header-anchor" href="#how-do-i-hillclimb-an-agent-with-a-coding-agent" aria-label="Permalink to "How do I hillclimb an agent with a coding agent?""></a></h2><p>Have Cursor read <a href="./../skills/hillclimb/SKILL.html"><code>skills/hillclimb/SKILL.md</code></a>.</p><p>Tell it:</p><ol><li><strong>Which agent</strong> you're improving (path or slug)</li><li><strong>One to three fixtures</strong> you'll reuse every round: a PR URL, a saved webhook body, or a canonical chat prompt</li><li><strong>What "better" means</strong> this round: correct tool choice, fewer tools, lower latency, or output quality. Name the freeze line too: API shape, public output, and existing evals that must stay green</li></ol><p>The skill serves the agent, hits your fixtures, reads the session trajectory, proposes one change, remeasures, and checks with you before the next round.</p><p>Other skills cover the edges:</p><table tabindex="0"><thead><tr><th>When you need…</th><th>Skill</th></tr></thead><tbody><tr><td>The measured improvement loop</td><td><a href="./../skills/hillclimb/SKILL.html"><code>skills/hillclimb/SKILL.md</code></a></td></tr><tr><td>An eval that locks a kept win</td><td><a href="./../skills/evals/SKILL.html"><code>skills/evals/SKILL.md</code></a></td></tr><tr><td>Repeatable GitHub webhook inputs</td><td><a href="./../skills/github/SKILL.html"><code>skills/github/SKILL.md</code></a></td></tr><tr><td>A run that misbehaves</td><td><a href="./../skills/debug/SKILL.html"><code>skills/debug/SKILL.md</code></a></td></tr></tbody></table><p>See <a href="./building-with-agents.html">Building agents with agents</a> for every framework skill and a good first prompt.</p><h2 id="what-do-i-need-before-a-hillclimb-round" tabindex="-1">What do I need before a hillclimb round? <a class="header-anchor" href="#what-do-i-need-before-a-hillclimb-round" aria-label="Permalink to "What do I need before a hillclimb round?""></a></h2><p>Agree on four things before you edit:</p><ol><li><strong>The target agent</strong>: the project you're improving</li><li><strong>Fixtures</strong>: one to three fixed inputs you can compare across runs</li><li><strong>Success criteria</strong>: what better means this round</li><li><strong>The freeze line</strong>: what must not change</li></ol><p>Pin the input first. A moving fixture is noise. For GitHub agents, use <code>agent-sdk github replay</code> (see the <a href="./guides/github.html">GitHub guide</a>). For a single tool without a model turn, use <code>agent-sdk call</code>. For a chat turn, use <code>agent-sdk run --dir . --message "…"</code>.</p><h2 id="how-do-i-run-one-hillclimb-round" tabindex="-1">How do I run one hillclimb round? <a class="header-anchor" href="#how-do-i-run-one-hillclimb-round" aria-label="Permalink to "How do I run one hillclimb round?""></a></h2><p><strong>Measure.</strong> Hit the agent the way a user would: playground, channel HTTP, or Slack in <code>--dev</code>. Or ask the hillclimb skill to do it. <code>agent-sdk run</code> returns a JSON trajectory and writes a trace under <code>.agent-
|
|
4
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> remeasure --> measure</span></span></code></pre></div><h2 id="how-do-i-hillclimb-an-agent-with-a-coding-agent" tabindex="-1">How do I hillclimb an agent with a coding agent? <a class="header-anchor" href="#how-do-i-hillclimb-an-agent-with-a-coding-agent" aria-label="Permalink to "How do I hillclimb an agent with a coding agent?""></a></h2><p>Have Cursor read <a href="./../skills/hillclimb/SKILL.html"><code>skills/hillclimb/SKILL.md</code></a>.</p><p>Tell it:</p><ol><li><strong>Which agent</strong> you're improving (path or slug)</li><li><strong>One to three fixtures</strong> you'll reuse every round: a PR URL, a saved webhook body, or a canonical chat prompt</li><li><strong>What "better" means</strong> this round: correct tool choice, fewer tools, lower latency, or output quality. Name the freeze line too: API shape, public output, and existing evals that must stay green</li></ol><p>The skill serves the agent, hits your fixtures, reads the session trajectory, proposes one change, remeasures, and checks with you before the next round.</p><p>Other skills cover the edges:</p><table tabindex="0"><thead><tr><th>When you need…</th><th>Skill</th></tr></thead><tbody><tr><td>The measured improvement loop</td><td><a href="./../skills/hillclimb/SKILL.html"><code>skills/hillclimb/SKILL.md</code></a></td></tr><tr><td>An eval that locks a kept win</td><td><a href="./../skills/evals/SKILL.html"><code>skills/evals/SKILL.md</code></a></td></tr><tr><td>Repeatable GitHub webhook inputs</td><td><a href="./../skills/github/SKILL.html"><code>skills/github/SKILL.md</code></a></td></tr><tr><td>A run that misbehaves</td><td><a href="./../skills/debug/SKILL.html"><code>skills/debug/SKILL.md</code></a></td></tr></tbody></table><p>See <a href="./building-with-agents.html">Building agents with agents</a> for every framework skill and a good first prompt.</p><h2 id="what-do-i-need-before-a-hillclimb-round" tabindex="-1">What do I need before a hillclimb round? <a class="header-anchor" href="#what-do-i-need-before-a-hillclimb-round" aria-label="Permalink to "What do I need before a hillclimb round?""></a></h2><p>Agree on four things before you edit:</p><ol><li><strong>The target agent</strong>: the project you're improving</li><li><strong>Fixtures</strong>: one to three fixed inputs you can compare across runs</li><li><strong>Success criteria</strong>: what better means this round</li><li><strong>The freeze line</strong>: what must not change</li></ol><p>Pin the input first. A moving fixture is noise. For GitHub agents, use <code>agent-sdk github replay</code> (see the <a href="./guides/github.html">GitHub guide</a>). For a single tool without a model turn, use <code>agent-sdk call</code>. For a chat turn, use <code>agent-sdk run --dir . --message "…"</code>.</p><h2 id="how-do-i-run-one-hillclimb-round" tabindex="-1">How do I run one hillclimb round? <a class="header-anchor" href="#how-do-i-run-one-hillclimb-round" aria-label="Permalink to "How do I run one hillclimb round?""></a></h2><p><strong>Measure.</strong> Hit the agent the way a user would: playground, channel HTTP, or Slack in <code>--dev</code>. Or ask the hillclimb skill to do it. <code>agent-sdk run</code> returns a JSON trajectory and writes a trace under <code>.agent-serve/traces/</code>.</p><p><strong>Reflect.</strong> Score the trajectory, not impressions. Was the answer right? Did the model thrash (too many tools, fat evidence, grep loops)? Did it invent work the host should have prepared? Name the single dominant problem for this round in one sentence. Example: "Full-file dumps trigger grep loops."</p><p><strong>Change one lever.</strong> Prefer the smallest change that addresses that problem:</p><ol><li>Host prep: seed what the model needs so it doesn't hunt</li><li>Evidence shape: trim or reorder artifacts</li><li>Instructions and skills: tighten the procedure</li><li>Tool surface: remove or gate tools that invite wandering</li><li>Framework changes: only when the agent can't express the fix</li></ol><p><strong>Remeasure.</strong> Same fixtures. Diff tools, wall time, and quality side by side. Keep the change only if the target metric improves and the freeze line holds.</p><h2 id="how-do-i-lock-a-hillclimb-improvement-with-an-eval" tabindex="-1">How do I lock a hillclimb improvement with an eval? <a class="header-anchor" href="#how-do-i-lock-a-hillclimb-improvement-with-an-eval" aria-label="Permalink to "How do I lock a hillclimb improvement with an eval?""></a></h2><p>Every kept change needs an eval that would have failed before the change: a tool-choice gate, an <code>action.result</code> count bound, or an output-shape check. Run <code>agent-sdk eval --dir . --json</code> between rounds. Never weaken an existing gate to pass the round.</p><p>Details live in <a href="./evals.html">Evals</a>. The evals skill will author the case with you.</p><h2 id="what-habits-help-hillclimbing-stay-reliable" tabindex="-1">What habits help hillclimbing stay reliable? <a class="header-anchor" href="#what-habits-help-hillclimbing-stay-reliable" aria-label="Permalink to "What habits help hillclimbing stay reliable?""></a></h2><ul><li>One problem per round. Don't bundle "trim evidence and rewrite instructions" unless you chose that on purpose.</li><li>Keep fixtures fixed until you deliberately need a harder case.</li><li>Separate host work from model tools when you blame latency. Moving deterministic prep onto the host is often the biggest win. In one PR reviewer, host-prepared evidence cut turns from about 8 minutes to about 1 minute.</li><li>Spot-check quality on at least one fixture against a known-good answer. Efficiency-only climbs quietly drop findings.</li><li>Treat <code>turn.failed</code> with <code>"turn interrupted"</code> as expected when a follow-up or stop preempted the turn.</li><li>Don't deploy, post to real surfaces, or weaken evals as part of a climb.</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="./evals.html">Evals</a></li><li><a href="./building-with-agents.html">Building agents with agents</a></li><li><a href="./guides/github.html">GitHub guide</a></li><li><a href="./troubleshooting.html">Fix common agent problems</a></li></ul>`,31)])])}const p=t(o,[["render",n]]);export{m as __pageData,p as default};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import{_ as a,c as t,o as s,ag as n}from"./chunks/framework.CAZyNGu9.js";const g=JSON.parse('{"title":"Agent SDK documentation","description":"Build your own software factory with Cursor agents as ordinary files: tools, approvals, channels, and evals.","frontmatter":{"title":"Agent SDK documentation","description":"Build your own software factory with Cursor agents as ordinary files: tools, approvals, channels, and evals."},"headers":[],"relativePath":"index.md","filePath":"README.md"}'),i={name:"index.md"};function o(r,e,l,h,d,p){return s(),t("div",null,[...e[0]||(e[0]=[n(`<h1 id="agent-sdk-documentation" tabindex="-1">Agent SDK documentation <a class="header-anchor" href="#agent-sdk-documentation" aria-label="Permalink to "Agent SDK documentation""></a></h1><p>The Agent SDK helps you build your own software factory: agents that inspect builds, review pull requests, gate promotions, and wake from Slack or GitHub when work arrives. You author each agent as ordinary files in a TypeScript project under <code>agent/</code>: markdown for agent instruction prompts, TypeScript for typed behavior. The framework discovers those files, and serves the agent over channels. The Cursor SDK and the Cursor harness run the turns.</p><p>You write the tools, instructions, channels, and evals. In return you get a factory you can version, test, and ship: side effects stay behind human approvals, and every change stays regression-checked.</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>my-agent/</span></span>
|
|
2
|
+
<span class="line"><span>├── package.json</span></span>
|
|
3
|
+
<span class="line"><span>├── agent/</span></span>
|
|
4
|
+
<span class="line"><span>│ ├── agent.ts # runtime config: model, local/cloud runtime</span></span>
|
|
5
|
+
<span class="line"><span>│ ├── instructions.md # the always-on system prompt</span></span>
|
|
6
|
+
<span class="line"><span>│ ├── tools/ # one typed tool per file</span></span>
|
|
7
|
+
<span class="line"><span>│ ├── skills/ # on-demand procedures (SKILL.md convention)</span></span>
|
|
8
|
+
<span class="line"><span>│ ├── mcp-connections/ # tools from external MCP servers</span></span>
|
|
9
|
+
<span class="line"><span>│ ├── subagents/ # specialist child agents</span></span>
|
|
10
|
+
<span class="line"><span>│ ├── channels/ # HTTP / Slack / GitHub surfaces</span></span>
|
|
11
|
+
<span class="line"><span>│ ├── hooks/ # observe the runtime event stream</span></span>
|
|
12
|
+
<span class="line"><span>│ ├── ab.ts # optional live A/B experiment</span></span>
|
|
13
|
+
<span class="line"><span>│ ├── ab/ # optional: more experiments</span></span>
|
|
14
|
+
<span class="line"><span>│ ├── schedules/ # cron-driven runs</span></span>
|
|
15
|
+
<span class="line"><span>│ ├── sandbox/workspace/ # files seeded into each session workspace</span></span>
|
|
16
|
+
<span class="line"><span>│ └── lib/ # shared code (import-only, never discovered)</span></span>
|
|
17
|
+
<span class="line"><span>└── evals/ # filesystem evals (regression checks)</span></span></code></pre></div><p>Bootstrap a project with nothing installed beyond Node:</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;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @cursor/july</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> init</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ./my-agent</span></span>
|
|
18
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> my-agent</span></span>
|
|
19
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev</span></span></code></pre></div><p><code>init</code> scaffolds the project, runs <code>npm install</code>, and offers a Cursor sign-in. The install puts the <code>agent-sdk</code> bin on the project's path, so <code>npx agent-sdk</code> resolves locally from then on.</p><p>Browse the docs locally without serving an agent:</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;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @cursor/july</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> docs</span></span></code></pre></div><p>Every running serve host also mounts this documentation at <code>/docs</code> (disable it with <code>--no-docs</code>).</p><h2 id="where-to-start" tabindex="-1">Where to start <a class="header-anchor" href="#where-to-start" aria-label="Permalink to "Where to start""></a></h2><p>Pick your entry point based on your goal.</p><table tabindex="0"><thead><tr><th>You are...</th><th>Start with</th></tr></thead><tbody><tr><td>New to the Agent SDK</td><td><a href="./quickstart.html">Quickstart</a> (PR approver), then <a href="./concepts.html">Concepts</a></td></tr><tr><td>Building a new agent with Cursor</td><td><a href="./scaffolding-agents.html">Scaffold an agent with Cursor</a></td></tr><tr><td>Learning from working agents</td><td><a href="./example-agents/">Example agents</a></td></tr><tr><td>Wiring an agent to Slack</td><td><a href="./guides/slack.html">Slack guide</a></td></tr><tr><td>Wiring an agent to GitHub webhooks</td><td><a href="./guides/github.html">GitHub guide</a></td></tr><tr><td>Driving an agent from Linear (or another tracker)</td><td><a href="./guides/webhooks.html#example-linear-as-the-control-plane">Webhooks guide: Linear example</a></td></tr><tr><td>Making an existing agent measurably better</td><td><a href="./evals.html">Evals</a>, then <a href="./hillclimbing.html">Hillclimbing</a></td></tr><tr><td>Comparing variants on live traffic</td><td><a href="./ab.html">Live A/B metrics</a></td></tr><tr><td>Deploying with Cursor or on your own infrastructure</td><td><a href="./deployment.html">Deployment</a></td></tr><tr><td>Debugging something that misbehaves</td><td><a href="./troubleshooting.html">Fix common agent problems</a></td></tr></tbody></table><h2 id="the-documentation" tabindex="-1">The documentation <a class="header-anchor" href="#the-documentation" aria-label="Permalink to "The documentation""></a></h2><p><strong>Core</strong></p><ul><li><a href="./quickstart.html">Quickstart</a>: build a PR approver that reviews by complexity and wakes from webhooks.</li><li><a href="./scaffolding-agents.html">Scaffold an agent with Cursor</a>: use the bundled skill for a guided build.</li><li><a href="./concepts.html">Concepts</a>: the mental model behind the framework.</li></ul><p><strong>Self-improving Agents</strong></p><ul><li><a href="./building-with-agents.html">Building agents with agents</a>: use a coding agent to scaffold, run, and iterate on your agent.</li><li><a href="./evals.html">Evals</a>: author <code>defineEval</code> cases, pick fixtures, and use evals as regression checks.</li><li><a href="./ab.html">Live A/B metrics</a>: assign sticky variants and compare cumulative metrics on live sessions.</li><li><a href="./storage.html">Storage</a>: point durable storage at a backend you own with <code>defineStorage</code>.</li><li><a href="./hillclimbing.html">Hillclimbing</a>: make an agent better one measured round at a time.</li></ul><p><strong>Guides</strong></p><ul><li><a href="./guides/webhooks.html">Webhooks and custom channels</a>: give the agent its own HTTP surface.</li><li><a href="./guides/github.html">GitHub</a>: wake the agent from pull requests, CI, and comments.</li><li><a href="./guides/slack.html">Slack</a>: put the agent in Slack over Socket Mode.</li><li><a href="./guides/human-in-the-loop.html">Human-in-the-loop approvals</a>: park a tool call until a person signs off.</li><li><a href="./guides/mcp-oauth.html">Host MCP OAuth</a>: authorize <code>oauth: true</code> connections, store tokens locally, and <code>--store</code> them on hosted deployments.</li><li><a href="./guides/agent-to-agent.html">Agent-to-agent</a>: every agent is an MCP server; agents can delegate to each other.</li><li><a href="./guides/cloud-runtime.html">Cloud runtime</a>: run turns on Cursor cloud agents instead of the local harness.</li></ul><p><strong>Example agents</strong></p><ul><li><a href="./example-agents/">Choose the right example</a>: compare all twelve agents by runtime, channels, tools, state, and architecture.</li><li><a href="./example-agents/weather-agent.html">Weather agent</a>: explore tools, MCP, approvals, skills, subagents, schedules, hooks, A/B metrics, and evals.</li><li><a href="./example-agents/slack-agent.html">Slack agent</a>: put a minimal agent in Slack through an account-linked transport.</li><li><a href="./example-agents/concierge.html">Concierge</a>: delegate work to a peer agent with its own context and sessions.</li><li><a href="./example-agents/benny.html">Playbook router</a>: route Slack intake through inherited repository playbooks.</li><li><a href="./example-agents/oncall.html">Alert investigator</a>: watch a Slack alerts channel and pin a self-rechecking investigation to every alert thread.</li><li><a href="./example-agents/bugbot.html">PR evidence reviewer</a>: review a host-prepared, diff-first pull-request evidence tree.</li><li><a href="./example-agents/approval-buddy.html">Approval Buddy</a>: keep approval policy in code while subagents supply review findings.</li><li><a href="./example-agents/security-reviewer.html">Security Reviewer</a>: run a staged, parallel security pipeline with live playground progress.</li><li><a href="./example-agents/fsd.html">Remote PR coordinator</a>: hand PR triage from local chat and webhooks to durable remote sessions.</li><li><a href="./example-agents/knowledge-base.html">Knowledge base</a>: turn conversations about people, systems, decisions, and preferences into shared markdown.</li><li><a href="./example-agents/codebase-wiki.html">Codebase wiki</a>: ingest merged PRs into per-feature pages with a daily digest schedule.</li><li><a href="./example-agents/codeowners-review.html">Codeowners review</a>: route PR reviews by ownership to per-area playbooks and aggregate verdicts.</li></ul><p><strong>Operating</strong></p><ul><li><a href="./deployment.html">Deployment</a>: Cursor-managed hosting, self-hosting, auth, state, and operations.</li><li><a href="./troubleshooting.html">Fix common agent problems</a>: symptom to cause, in plain language.</li></ul><p><strong>Reference</strong></p><ul><li><a href="./reference/project-layout.html">Project layout</a>: the full folder structure.</li><li><a href="./reference/agent-config.html">Agent config</a> · <a href="./reference/instructions.html">Instructions</a> · <a href="./reference/tools.html">Tools</a> · <a href="./reference/prompt.html"><code>prompt</code></a> · <a href="./reference/skills.html">Skills</a> · <a href="./reference/connections.html">MCP connections</a> · <a href="./reference/subagents.html">Subagents</a></li><li><a href="./reference/channels.html">Channels</a> · <a href="./reference/schedules.html">Schedules and reminders</a> · <a href="./reference/hooks.html">Hooks</a> · <a href="./reference/sessions.html">Sessions and streaming</a> · <a href="./reference/playground.html">Playground</a></li><li><a href="./reference/cli.html">CLI</a> · <a href="./reference/http-api.html">HTTP API</a></li></ul><h2 id="run-the-cli" tabindex="-1">Run the CLI <a class="header-anchor" href="#run-the-cli" aria-label="Permalink to "Run the CLI""></a></h2><p>The docs write commands as <code>agent-sdk <command></code>. Where that command comes from depends on where you run. Starting fresh? This works with no prior install:</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;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @cursor/july</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> init</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ./my-agent</span></span>
|
|
20
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> my-agent</span></span>
|
|
21
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev</span></span></code></pre></div><div class="note custom-block github-alert"><p class="custom-block-title">NOTE</p><p>When running from a source checkout there is no installed bin. Alias it from the package directory:</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:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> packages/agent-serve</span></span>
|
|
22
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">alias</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> agent-sdk</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"pnpm exec tsx </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">$PWD</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">/src/bin/agent-serve.ts"</span></span></code></pre></div><p>When <code>@cursor/july</code> is installed as a dependency, the <code>agent-sdk</code> bin is on your package manager's path (<code>pnpm exec agent-sdk</code>, <code>npx agent-sdk</code>). <code>npx @cursor/july docs</code> runs the <code>july</code> bin with that command (no local install required).</p></div><div class="note custom-block github-alert"><p class="custom-block-title">NOTE</p><p>The framework is being renamed from agent-serve to the Agent SDK. The <code>agent-sdk</code> bin already ships (alongside <code>july</code>, <code>agentkit</code>, and the legacy <code>agent-serve</code> alias), and projects already import from <code>@cursor/july</code>. A few on-disk names keep their old form until the code rename ships:</p><table tabindex="0"><thead><tr><th>Future name</th><th>Current name</th></tr></thead><tbody><tr><td><code>.agent-sdk/</code> state directory</td><td><code>.agent-serve/</code></td></tr><tr><td><code>/var/lib/agent-sdk</code> (deploy state root)</td><td><code>/var/lib/agent-serve</code></td></tr><tr><td><code>CURSOR_AGENT_SDK_*</code> env vars</td><td><code>AGENT_SERVE_*</code></td></tr><tr><td>Package path <code>packages/agent-sdk</code></td><td><code>packages/agent-serve</code></td></tr></tbody></table></div><div class="warning custom-block github-alert"><p class="custom-block-title">WARNING</p><p>Run the Agent SDK with Node 22.13 or newer, and never with Bun. Bun's HTTP/2 client corrupts the Cursor SDK's tool-result streams (<code>NGHTTP2_FRAME_SIZE_ERROR</code>), so every built-in read or grep the model makes fails and turns degrade into minutes-long retry loops.</p></div><h2 id="credentials" tabindex="-1">Credentials <a class="header-anchor" href="#credentials" aria-label="Permalink to "Credentials""></a></h2><p>Model turns run on the Cursor harness, so the serving host needs a Cursor credential. Sign in once, or export an API key:</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;"> login</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # browser sign-in; mints + stores a revocable API key</span></span>
|
|
23
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># or: export CURSOR_API_KEY=key_...</span></span>
|
|
24
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> whoami</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # which account powers this host, and why</span></span></code></pre></div><h2 id="related-documentation" tabindex="-1">Related documentation <a class="header-anchor" href="#related-documentation" aria-label="Permalink to "Related documentation""></a></h2><p>These docs describe behavior. The package <a href="./../README.html"><code>README.md</code></a> is the compact reference, and <a href="./../AGENTS.html"><code>AGENTS.md</code></a> is the coding-agent cheat sheet. Task-shaped guides that ship with the package live under <a href="./../skills/"><code>skills/</code></a>; point a coding agent working on an Agent SDK project at them first. When the docs and the code disagree, the code is authoritative. Fix the doc.</p>`,37)])])}const u=a(i,[["render",o]]);export{g as __pageData,u as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as a,c as t,o as s,ag as n}from"./chunks/framework.CAZyNGu9.js";const g=JSON.parse('{"title":"Agent SDK documentation","description":"Build your own software factory with Cursor agents as ordinary files: tools, approvals, channels, and evals.","frontmatter":{"title":"Agent SDK documentation","description":"Build your own software factory with Cursor agents as ordinary files: tools, approvals, channels, and evals."},"headers":[],"relativePath":"index.md","filePath":"README.md"}'),i={name:"index.md"};function o(r,e,l,d,
|
|
1
|
+
import{_ as a,c as t,o as s,ag as n}from"./chunks/framework.CAZyNGu9.js";const g=JSON.parse('{"title":"Agent SDK documentation","description":"Build your own software factory with Cursor agents as ordinary files: tools, approvals, channels, and evals.","frontmatter":{"title":"Agent SDK documentation","description":"Build your own software factory with Cursor agents as ordinary files: tools, approvals, channels, and evals."},"headers":[],"relativePath":"index.md","filePath":"README.md"}'),i={name:"index.md"};function o(r,e,l,h,d,p){return s(),t("div",null,[...e[0]||(e[0]=[n("",37)])])}const u=a(i,[["render",o]]);export{g as __pageData,u as default};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import{_ as i,c as a,o as n,ag as t}from"./chunks/framework.CAZyNGu9.js";const o=JSON.parse('{"title":"Build your first PR approver","description":"Create an agent that reviews pull requests by complexity, approves the safe ones, and wakes from GitHub webhooks.","frontmatter":{"title":"Build your first PR approver","description":"Create an agent that reviews pull requests by complexity, approves the safe ones, and wakes from GitHub webhooks."},"headers":[],"relativePath":"quickstart.md","filePath":"quickstart.md"}'),e={name:"quickstart.md"};function h(l,s,p,k,r,d){return n(),a("div",null,[...s[0]||(s[0]=[t(`<h1 id="build-your-first-pr-approver" tabindex="-1">Build your first PR approver <a class="header-anchor" href="#build-your-first-pr-approver" aria-label="Permalink to "Build your first PR approver""></a></h1><p>Build an agent that reviews GitHub pull requests. It fetches the diff, rates the change's complexity in plain TypeScript, approves the safe ones, and flags the rest for a human. Then wire it to GitHub webhooks and watch a pull request wake it.</p><p>The split is the point of the exercise: deterministic policy lives in typed tools, judgment lives in the model, and every decision is inspectable in the playground.</p><h2 id="prerequisites" tabindex="-1">Prerequisites <a class="header-anchor" href="#prerequisites" aria-label="Permalink to "Prerequisites""></a></h2><p>You need:</p><ul><li>Node 22.13 or newer. Bun isn't supported.</li><li>The <code>agent-sdk</code> CLI. See <a href="./README.html#run-the-cli">Run the CLI</a> for
|
|
1
|
+
import{_ as i,c as a,o as n,ag as t}from"./chunks/framework.CAZyNGu9.js";const o=JSON.parse('{"title":"Build your first PR approver","description":"Create an agent that reviews pull requests by complexity, approves the safe ones, and wakes from GitHub webhooks.","frontmatter":{"title":"Build your first PR approver","description":"Create an agent that reviews pull requests by complexity, approves the safe ones, and wakes from GitHub webhooks."},"headers":[],"relativePath":"quickstart.md","filePath":"quickstart.md"}'),e={name:"quickstart.md"};function h(l,s,p,k,r,d){return n(),a("div",null,[...s[0]||(s[0]=[t(`<h1 id="build-your-first-pr-approver" tabindex="-1">Build your first PR approver <a class="header-anchor" href="#build-your-first-pr-approver" aria-label="Permalink to "Build your first PR approver""></a></h1><p>Build an agent that reviews GitHub pull requests. It fetches the diff, rates the change's complexity in plain TypeScript, approves the safe ones, and flags the rest for a human. Then wire it to GitHub webhooks and watch a pull request wake it.</p><p>The split is the point of the exercise: deterministic policy lives in typed tools, judgment lives in the model, and every decision is inspectable in the playground.</p><h2 id="prerequisites" tabindex="-1">Prerequisites <a class="header-anchor" href="#prerequisites" aria-label="Permalink to "Prerequisites""></a></h2><p>You need:</p><ul><li>Node 22.13 or newer. Bun isn't supported.</li><li>The <code>agent-sdk</code> CLI. <code>npx @cursor/july init ./pr-approver</code> bootstraps it with no prior install: <code>init</code> scaffolds the project, runs <code>npm install</code>, and offers a Cursor sign-in, after which <code>npx agent-sdk</code> resolves from the project's own dependencies. See <a href="./README.html#run-the-cli">Run the CLI</a> for other setups, such as a monorepo source checkout.</li><li>A Cursor credential for model turns. Sign in once:</li></ul><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;"> login</span></span></code></pre></div><p>You can also set <code>CURSOR_API_KEY</code> instead of signing in.</p><ul><li>A GitHub credential. <code>gh auth login</code> is enough, or set <code>GITHUB_TOKEN</code>. The tools you write resolve either one automatically. Reading pull requests works on any public repo; posting reviews needs write access to the repo you review.</li></ul><h2 id="first-run-in-10-minutes" tabindex="-1">First run in 10 minutes <a class="header-anchor" href="#first-run-in-10-minutes" aria-label="Permalink to "First run in 10 minutes""></a></h2><p>Want a working agent before the full tutorial? Four commands get you there:</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;"> init</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ./pr-approver</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # scaffold + npm install + sign-in offer</span></span>
|
|
2
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> pr-approver</span></span>
|
|
3
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # serve, and print the playground URL</span></span></code></pre></div><p>Open the playground URL and chat with the scaffold. Then, in a second terminal (<code>dev</code> keeps running), run one turn from the command line:</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;"> run</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;"> --message</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "Introduce yourself in one sentence."</span></span></code></pre></div><p>That's the whole loop: files become an agent, <code>dev</code> serves it, and <code>run</code> exercises it. The rest of this page turns that scaffold into a real PR approver.</p><h2 id="scaffolding-agents" tabindex="-1">Scaffolding Agents <a class="header-anchor" href="#scaffolding-agents" aria-label="Permalink to "Scaffolding Agents""></a></h2><p>Have Cursor read <a href="./../skills/create-agent/SKILL.html"><code>skills/create-agent/SKILL.md</code></a> and describe what you want:</p><blockquote><p>Build me a PR approver for the playground. Start with one tool that inspects a pull request and guide me through the remaining decisions.</p></blockquote><p>Cursor asks for missing choices, shows you the plan, then builds and verifies the agent. Continue below to do the same by hand.</p><p>See <a href="./scaffolding-agents.html">Scaffold an agent with Cursor</a> for the full guided workflow.</p><h2 id="create-your-project" tabindex="-1">Create your project <a class="header-anchor" href="#create-your-project" aria-label="Permalink to "Create your project""></a></h2><p>Start with the built-in scaffold:</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;"> init</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ./pr-approver</span></span>
|
|
2
4
|
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> pr-approver</span></span>
|
|
3
5
|
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev</span></span></code></pre></div><p>The scaffold creates the files the Agent SDK discovers, plus empty capability folders (each with a <code>.gitkeep</code>) so you can drop tools, channels, and evals in place:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>pr-approver/</span></span>
|
|
4
6
|
<span class="line"><span>├── agent/</span></span>
|
|
@@ -11,15 +13,16 @@ import{_ as i,c as a,o as n,ag as t}from"./chunks/framework.CAZyNGu9.js";const o
|
|
|
11
13
|
<span class="line"><span>│ ├── subagents/</span></span>
|
|
12
14
|
<span class="line"><span>│ ├── channels/</span></span>
|
|
13
15
|
<span class="line"><span>│ ├── hooks/</span></span>
|
|
16
|
+
<span class="line"><span>│ │ └── memory.ts</span></span>
|
|
14
17
|
<span class="line"><span>│ ├── ab/</span></span>
|
|
15
18
|
<span class="line"><span>│ ├── schedules/</span></span>
|
|
16
19
|
<span class="line"><span>│ ├── sandbox/workspace/</span></span>
|
|
17
20
|
<span class="line"><span>│ └── lib/</span></span>
|
|
18
21
|
<span class="line"><span>├── evals/</span></span>
|
|
19
22
|
<span class="line"><span>├── package.json</span></span>
|
|
20
|
-
<span class="line"><span>└── tsconfig.json</span></span></code></pre></div><p><code>agent.ts</code> holds the model and runtime settings. <code>instructions.md</code> is the always-on system prompt. Each file under <code>agent/tools/</code> becomes a tool. <code>tsconfig.json</code> type-checks the project (<code>npm run check</code>); the framework runs your TypeScript directly, so nothing compiles.</p><p>
|
|
23
|
+
<span class="line"><span>└── tsconfig.json</span></span></code></pre></div><p><code>agent.ts</code> holds the model and runtime settings. <code>instructions.md</code> is the always-on system prompt, and the scaffold's version includes a memory section that tells the agent how to consult its journal. Each file under <code>agent/tools/</code> becomes a tool, and <code>agent/hooks/memory.ts</code> journals every turn so future sessions can recall past work (delete it to opt out). <code>tsconfig.json</code> type-checks the project (<code>npm run check</code>); the framework runs your TypeScript directly, so nothing compiles.</p><p><code>agent-sdk dev</code> blocks until you stop it. Keep it running and open a second terminal for every other command on this page, starting with these checks:</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;"> validate</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span></span>
|
|
21
24
|
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> info</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span></span></code></pre></div><p>These commands inspect the project without starting a model turn.</p><h2 id="run-your-agent" tabindex="-1">Run your agent <a class="header-anchor" href="#run-your-agent" aria-label="Permalink to "Run your agent""></a></h2><p>The scaffold already works. Run one turn from the terminal:</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;"> run</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;"> \\</span></span>
|
|
22
|
-
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --message</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "Introduce yourself in one sentence."</span></span></code></pre></div><p><code>run</code> starts the agent, sends the message, and waits for the final reply. It prints a JSON trajectory with the response, tool calls, and token usage. It also writes an NDJSON trace under <code>.agent-
|
|
25
|
+
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --message</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "Introduce yourself in one sentence."</span></span></code></pre></div><p><code>run</code> starts the agent, sends the message, and waits for the final reply. It prints a JSON trajectory with the response, tool calls, and token usage. It also writes an NDJSON trace under <code>.agent-serve/traces/</code>.</p><h2 id="teach-it-to-review" tabindex="-1">Teach it to review <a class="header-anchor" href="#teach-it-to-review" aria-label="Permalink to "Teach it to review""></a></h2><p>Replace <code>agent/instructions.md</code>:</p><div class="language-md vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">md</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold;"># PR approver</span></span>
|
|
23
26
|
<span class="line"></span>
|
|
24
27
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">You review GitHub pull requests. Be specific and brief.</span></span>
|
|
25
28
|
<span class="line"></span>
|
|
@@ -201,4 +204,4 @@ import{_ as i,c as a,o as n,ag as t}from"./chunks/framework.CAZyNGu9.js";const o
|
|
|
201
204
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># second terminal:</span></span>
|
|
202
205
|
<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/acme/checkout/pull/42</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> \\</span></span>
|
|
203
206
|
<span class="line"><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;"> --action</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> opened</span></span></code></pre></div><p>The replay prints the delivery, and the serve terminal shows the wake:</p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>[agent-sdk] replaying acme/checkout#42 (pull_request) → 1 channel</span></span>
|
|
204
|
-
<span class="line"><span>[agent-sdk] pull_request.opened → pr-approver/github 200</span></span></code></pre></div><p>The agent runs the same inspect-then-submit loop, unprompted this time. Replay the same PR again and the channel resumes that PR's session instead of starting a new one: each pull request keeps one running conversation.</p><h2 id="open-the-playground" tabindex="-1">Open the playground <a class="header-anchor" href="#open-the-playground" aria-label="Permalink to "Open the playground""></a></h2><p>Keep <code>agent-sdk dev</code> running and open the playground URL it printed. The webhook session is in the session list, titled <code>Review acme/checkout#42</code>, with the trigger message, both tool calls, and the verdict laid out. Start a new chat there and ask for another review to watch a turn stream live.</p><h2 id="go-live" tabindex="-1">Go live <a class="header-anchor" href="#go-live" aria-label="Permalink to "Go live""></a></h2><p>Replay is for development. For real deliveries, serve with <code>--cursor-events --repo owner/repo</code> to pull events for repositories connected to Cursor with no public URL, or run <code>agent-sdk github forward</code> to relay webhooks to your dev server. The <a href="./guides/github.html">GitHub guide</a> compares the options. In production, give the host GitHub App credentials so reviews post as your app's bot identity instead of a personal account.</p><h2 id="where-to-go-next" tabindex="-1">Where to go next <a class="header-anchor" href="#where-to-go-next" aria-label="Permalink to "Where to go next""></a></h2><ul><li><a href="./../examples/approval-buddy/"><code>examples/approval-buddy</code></a>: the production-shaped sibling, with commit statuses, review subagents, and a deterministic stamp policy</li><li><a href="./evals.html">Evals</a>: freeze these two PRs as regression checks so prompt changes can't flip a verdict</li><li><a href="./reference/tools.html">Tools</a>: more on typed tools, approvals, and direct calls</li><li><a href="./guides/github.html">GitHub</a>: fixtures, forwarding, and pulling events from Cursor</li><li><a href="./building-with-agents.html">Building agents with agents</a>: have a coding agent extend the project for you</li></ul>`,
|
|
207
|
+
<span class="line"><span>[agent-sdk] pull_request.opened → pr-approver/github 200</span></span></code></pre></div><p>The agent runs the same inspect-then-submit loop, unprompted this time. Replay the same PR again and the channel resumes that PR's session instead of starting a new one: each pull request keeps one running conversation.</p><h2 id="open-the-playground" tabindex="-1">Open the playground <a class="header-anchor" href="#open-the-playground" aria-label="Permalink to "Open the playground""></a></h2><p>Keep <code>agent-sdk dev</code> running and open the playground URL it printed. The webhook session is in the session list, titled <code>Review acme/checkout#42</code>, with the trigger message, both tool calls, and the verdict laid out. Start a new chat there and ask for another review to watch a turn stream live.</p><h2 id="go-live" tabindex="-1">Go live <a class="header-anchor" href="#go-live" aria-label="Permalink to "Go live""></a></h2><p>Replay is for development. For real deliveries, serve with <code>--cursor-events --repo owner/repo</code> to pull events for repositories connected to Cursor with no public URL, or run <code>agent-sdk github forward</code> to relay webhooks to your dev server. The <a href="./guides/github.html">GitHub guide</a> compares the options. In production, give the host GitHub App credentials so reviews post as your app's bot identity instead of a personal account.</p><h2 id="where-to-go-next" tabindex="-1">Where to go next <a class="header-anchor" href="#where-to-go-next" aria-label="Permalink to "Where to go next""></a></h2><ul><li><a href="./../examples/approval-buddy/"><code>examples/approval-buddy</code></a>: the production-shaped sibling, with commit statuses, review subagents, and a deterministic stamp policy</li><li><a href="./evals.html">Evals</a>: freeze these two PRs as regression checks so prompt changes can't flip a verdict</li><li><a href="./reference/tools.html">Tools</a>: more on typed tools, approvals, and direct calls</li><li><a href="./guides/github.html">GitHub</a>: fixtures, forwarding, and pulling events from Cursor</li><li><a href="./building-with-agents.html">Building agents with agents</a>: have a coding agent extend the project for you</li></ul>`,81)])])}const g=i(e,[["render",h]]);export{o as __pageData,g as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as i,c as a,o as n,ag as t}from"./chunks/framework.CAZyNGu9.js";const o=JSON.parse('{"title":"Build your first PR approver","description":"Create an agent that reviews pull requests by complexity, approves the safe ones, and wakes from GitHub webhooks.","frontmatter":{"title":"Build your first PR approver","description":"Create an agent that reviews pull requests by complexity, approves the safe ones, and wakes from GitHub webhooks."},"headers":[],"relativePath":"quickstart.md","filePath":"quickstart.md"}'),e={name:"quickstart.md"};function h(l,s,p,k,r,d){return n(),a("div",null,[...s[0]||(s[0]=[t("",
|
|
1
|
+
import{_ as i,c as a,o as n,ag as t}from"./chunks/framework.CAZyNGu9.js";const o=JSON.parse('{"title":"Build your first PR approver","description":"Create an agent that reviews pull requests by complexity, approves the safe ones, and wakes from GitHub webhooks.","frontmatter":{"title":"Build your first PR approver","description":"Create an agent that reviews pull requests by complexity, approves the safe ones, and wakes from GitHub webhooks."},"headers":[],"relativePath":"quickstart.md","filePath":"quickstart.md"}'),e={name:"quickstart.md"};function h(l,s,p,k,r,d){return n(),a("div",null,[...s[0]||(s[0]=[t("",81)])])}const g=i(e,[["render",h]]);export{o as __pageData,g as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{_ as e,c as i,o as a,ag as t}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically.","frontmatter":{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically."},"headers":[],"relativePath":"reference/agent-config.md","filePath":"reference/agent-config.md"}'),n={name:"reference/agent-config.md"};function o(
|
|
1
|
+
import{_ as e,c as i,o as a,ag as t}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically.","frontmatter":{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically."},"headers":[],"relativePath":"reference/agent-config.md","filePath":"reference/agent-config.md"}'),n={name:"reference/agent-config.md"};function o(d,s,l,r,h,c){return a(),i("div",null,[...s[0]||(s[0]=[t(`<h1 id="agent-config-agent-agent-ts" tabindex="-1">Agent config (<code>agent/agent.ts</code>) <a class="header-anchor" href="#agent-config-agent-agent-ts" aria-label="Permalink to "Agent config (\`agent/agent.ts\`)""></a></h1><p><code>agent/agent.ts</code> default-exports <code>defineAgent(config)</code>: which model runs the agent, where turns execute, and runtime-specific defaults. Everything is optional on the root agent.</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
2
|
<span class="line"></span>
|
|
3
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
4
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> model: {</span></span>
|
|
@@ -13,13 +13,15 @@ import{_ as e,c as i,o as a,ag as t}from"./chunks/framework.CAZyNGu9.js";const k
|
|
|
13
13
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // repos: [{ url: "https://github.com/org/repo", startingRef: "main" }],</span></span>
|
|
14
14
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // },</span></span>
|
|
15
15
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // local: { cwd: "../harness" },</span></span>
|
|
16
|
-
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><h2 id="fields-on-defineagent" tabindex="-1">Fields on <code>defineAgent</code> <a class="header-anchor" href="#fields-on-defineagent" aria-label="Permalink to "Fields on \`defineAgent\`""></a></h2><p><code>defineAgent</code> accepts these fields.</p><table tabindex="0"><thead><tr><th>Field</th><th>Type</th><th>Meaning</th></tr></thead><tbody><tr><td><code>model</code></td><td>string or <code>{ id, params }</code></td><td>Cursor model for turns. Defaults to <code>grok-4.5</code> with <code>effort=high</code>, <code>fast=true</code> on the root agent. Subagents omit it to inherit.</td></tr><tr><td><code>name</code></td><td>string</td><td>Display name override. Defaults to the package name or directory name.</td></tr><tr><td><code>description</code></td><td>string</td><td>What the agent is for. Required on subagents; the parent model reads it to decide when to delegate. Documentation-only on the root.</td></tr><tr><td><code>instructions</code></td><td>string</td><td>Inline instructions. Prefer <code>instructions.md</code>; this exists for subagents and generated configs.</td></tr><tr><td><code>runtime</code></td><td><code>"local"</code> or <code>"cloud"</code></td><td>Where turns execute. Default <code>"local"</code>.</td></tr><tr><td><code>cloud</code></td><td>object</td><td>Cloud agent defaults: repos, env, envVars, forwarded to the Cursor SDK. Used when <code>runtime</code> is <code>"cloud"</code>, and as the base merged under per-session <code>cloud</code> send options.</td></tr><tr><td><code>local</code></td><td><code>{ cwd? }</code></td><td>Local harness defaults; ignored for cloud turns.</td></tr></tbody></table><h2 id="choose-a-model" tabindex="-1">Choose a model <a class="header-anchor" href="#choose-a-model" aria-label="Permalink to "Choose a model""></a></h2><p><code>model</code> is a Cursor model id string, or <code>{ id, params }</code>. Effort and speed are params, not id suffixes. The SDK rejects suffix-style ids like <code>grok-4.5-fast</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:#6F42C1;--shiki-dark:#B392F0;">model</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><h2 id="fields-on-defineagent" tabindex="-1">Fields on <code>defineAgent</code> <a class="header-anchor" href="#fields-on-defineagent" aria-label="Permalink to "Fields on \`defineAgent\`""></a></h2><p><code>defineAgent</code> accepts these fields.</p><table tabindex="0"><thead><tr><th>Field</th><th>Type</th><th>Meaning</th></tr></thead><tbody><tr><td><code>model</code></td><td>string or <code>{ id, params }</code></td><td>Cursor model for turns. Defaults to <code>grok-4.5</code> with <code>effort=high</code>, <code>fast=true</code> on the root agent. Subagents omit it to inherit.</td></tr><tr><td><code>name</code></td><td>string</td><td>Display name override. Defaults to the package name or directory name.</td></tr><tr><td><code>description</code></td><td>string</td><td>What the agent is for. Required on subagents; the parent model reads it to decide when to delegate. Documentation-only on the root.</td></tr><tr><td><code>instructions</code></td><td>string</td><td>Inline instructions. Prefer <code>instructions.md</code>; this exists for subagents and generated configs.</td></tr><tr><td><code>runtime</code></td><td><code>"local"</code> or <code>"cloud"</code></td><td>Where turns execute. Default <code>"local"</code>.</td></tr><tr><td><code>cloud</code></td><td>object</td><td>Cloud agent defaults: repos, env, envVars, forwarded to the Cursor SDK. Used when <code>runtime</code> is <code>"cloud"</code>, and as the base merged under per-session <code>cloud</code> send options.</td></tr><tr><td><code>local</code></td><td><code>{ cwd?, workspaceDir?, sandbox? }</code></td><td>Local harness defaults; ignored for cloud turns. See <a href="#local-options">Local options</a>.</td></tr><tr><td><code>hosting</code></td><td><code>{ egressDomains?, secretNames? }</code></td><td>Managed-hosting declarations read by <code>agent-sdk deploy</code>: the pod's egress allowlist and the secret names the agent expects. Ignored by local serving.</td></tr><tr><td><code>concurrency</code></td><td><code>{ maxRunningTurns? }</code></td><td>Engine-wide turn admission limit. See <a href="#concurrency">Concurrency</a>.</td></tr><tr><td><code>builtinTools</code></td><td><code>{ reminders? }</code></td><td>Framework-provided model-facing tools, opted in per capability. See <a href="#built-in-tools">Built-in tools</a>.</td></tr></tbody></table><h2 id="choose-a-model" tabindex="-1">Choose a model <a class="header-anchor" href="#choose-a-model" aria-label="Permalink to "Choose a model""></a></h2><p><code>model</code> is a Cursor model id string, or <code>{ id, params }</code>. Effort and speed are params, not id suffixes. The SDK rejects suffix-style ids like <code>grok-4.5-fast</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:#6F42C1;--shiki-dark:#B392F0;">model</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: {</span></span>
|
|
17
17
|
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> id</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"grok-4.5"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
18
18
|
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> params</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: [</span></span>
|
|
19
19
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { id: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"effort"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, value: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"high"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
20
20
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { id: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"fast"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, value: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"true"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
21
21
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ],</span></span>
|
|
22
|
-
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>A plain string works when you don't need params:</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;">model</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"composer-2.5"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span></code></pre></div><h2 id="choose-a-runtime" tabindex="-1">Choose a runtime <a class="header-anchor" href="#choose-a-runtime" aria-label="Permalink to "Choose a runtime""></a></h2><p><code>runtime: "local"</code> (the default) runs turns on the Cursor SDK harness on this machine. The session id doubles as the SDK agent id, and server tools, skills, sandbox seeds, and tool approvals all apply.</p><p><code>runtime: "cloud"</code> runs turns on Cursor cloud agents (<code>bc-…</code> ids). Pass a <code>cloud</code> block with the repos the VM carries.
|
|
22
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>A plain string works when you don't need params:</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;">model</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"composer-2.5"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span></code></pre></div><h2 id="choose-a-runtime" tabindex="-1">Choose a runtime <a class="header-anchor" href="#choose-a-runtime" aria-label="Permalink to "Choose a runtime""></a></h2><p><code>runtime: "local"</code> (the default) runs turns on the Cursor SDK harness on this machine. The session id doubles as the SDK agent id, and server tools, skills, sandbox seeds, and tool approvals all apply.</p><p><code>runtime: "cloud"</code> runs turns on Cursor cloud agents (<code>bc-…</code> ids). Pass a <code>cloud</code> block with the repos the VM carries. Server tools stay reachable over authenticated HTTP MCP back to the serve host when <code>--public-url</code> or <code>--cloud-tools-url</code> is set (omitted with a warning otherwise), and instructions and agent-tool catalogs are prepended to the first prompt, because the local session workspace is not the cloud VM.</p><p><code>validate</code> warns when <code>runtime: "cloud"</code> is combined with agent tools, skills, or sandbox seeds, which only materialize into local session workspaces, and when the <code>cloud</code> block is missing. The full capability matrix and the patterns that hold up are in the <a href="./../guides/cloud-runtime.html">Cloud runtime guide</a>.</p><h2 id="local-options" tabindex="-1">Local options <a class="header-anchor" href="#local-options" aria-label="Permalink to "Local options""></a></h2><p><code>local</code> sets local-harness defaults, all ignored for cloud turns.</p><p><code>local.workspaceDir</code> points every session at one shared harness cwd, for agents that work inside an existing checkout. It takes precedence over <code>cwd</code>, and a per-send <code>workspaceDir</code> still wins over both. The SDK keys its local executor (rules, skills, MCP, ignore mappings) on the harness cwd, so a shared directory resolves the workspace once per serve process instead of once per session. The trade: sessions share a working tree, so a file one turn writes is visible to the next.</p><p><code>local.sandbox</code> runs the harness inside Cursor's local sandbox. It's off by default, matching the SDK: shell then auto-approves and inherits the serve process environment, including any credentials the host holds. Turn it on for agents whose turns read untrusted input (webhook payloads, PR diffs, inbound chat); it's a real tool boundary rather than a prompt-level one.</p><h3 id="local-cwd" tabindex="-1">Local cwd <a class="header-anchor" href="#local-cwd" aria-label="Permalink to "Local cwd""></a></h3><p><code>local.cwd</code> sets the default parent directory for local harness workspaces. Each session uses <code><cwd>/<sessionId></code> (absolute, or relative to the project root) unless a per-send <code>workspaceDir</code> overrides it.</p><p>This is your control over ambient context. Session workspaces are real Cursor project directories, so the harness loads <code>AGENTS.md</code> and <code>.cursor</code> config from ancestor directories. An agent inside a big monorepo that must not inherit the monorepo's rules points <code>cwd</code> outside it (or runs with <code>--state-root</code> under <code>/tmp</code>). An agent that <em>needs</em> a specific checkout's skills and rules points <code>cwd</code> inside that checkout.</p><h2 id="the-cloud-block" tabindex="-1">The <code>cloud</code> block <a class="header-anchor" href="#the-cloud-block" aria-label="Permalink to "The \`cloud\` block""></a></h2><p>Cloud agent defaults forwarded to the Cursor SDK: <code>repos</code> (each <code>{ url, startingRef? }</code>), environment selection, <code>envVars</code>, and the rest. A local agent uses the same block as the base config when a channel opens a cloud-attached session per send. That hybrid pattern is covered in <a href="./../guides/cloud-runtime.html#hybrid-local-agent-cloud-sessions">Cloud runtime</a>.</p><h2 id="concurrency" tabindex="-1">Concurrency <a class="header-anchor" href="#concurrency" aria-label="Permalink to "Concurrency""></a></h2><p><code>concurrency.maxRunningTurns</code> caps how many model turns run at once across all of the agent's sessions (positive integer, hard cap 200). When every slot is busy, newly admitted turns queue FIFO instead of failing: the stream records a durable <code>turn.queued</code> event with the queue position, <code>GET /v1/sessions</code> reports <code>queued: true</code>, and each queued turn starts as soon as a slot frees. A queued turn still counts as running for busy semantics: follow-ups preempt it, and direct tool calls get <code>409 session_busy</code>. Omit for unlimited.</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;"> defineAgent</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
23
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> concurrency: { maxRunningTurns: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">3</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
24
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><h2 id="built-in-tools" tabindex="-1">Built-in tools <a class="header-anchor" href="#built-in-tools" aria-label="Permalink to "Built-in tools""></a></h2><p><code>builtinTools</code> opts into framework-provided model-facing tools. Each enabled capability materializes as ordinary server tools at discovery time, so turns, direct calls, <code>info</code>, and the playground treat them like authored tools. Authored tools with the same name win, with a warning, and like all server tools they run on the local runtime.</p><p><code>builtinTools: { reminders: true }</code> adds three tools bound to the current conversation over <code>host.reminders</code>: <code>reminders_create</code>, <code>reminders_list</code>, and <code>reminders_cancel</code>. Sessions without a continuation key can't arm reminders. See <a href="./schedules.html#reminders">Schedules and reminders</a>.</p><h2 id="generate-instructions" tabindex="-1">Generate instructions <a class="header-anchor" href="#generate-instructions" aria-label="Permalink to "Generate instructions""></a></h2><p>When the system prompt must be computed, author <code>agent/instructions.ts</code> instead of markdown:</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;"> { defineInstructions } </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>
|
|
23
25
|
<span class="line"></span>
|
|
24
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;"> defineInstructions</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
25
27
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> markdown: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`You are the on-call assistant for \${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">process</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">env</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">TEAM_NAME</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}.\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
@@ -31,4 +33,4 @@ import{_ as e,c as i,o as a,ag as t}from"./chunks/framework.CAZyNGu9.js";const k
|
|
|
31
33
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span>
|
|
32
34
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`listening on \${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">handle</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">url</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span>
|
|
33
35
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// handle.callTool(...), handle.dispatchSchedule("heartbeat"),</span></span>
|
|
34
|
-
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// handle.createReminder(...), handle.project, await handle.close()</span></span></code></pre></div><p><code>ServeOptions</code> mirrors the CLI flags: <code>port</code>, <code>host</code>, <code>dev</code>, <code>stateRoot</code>, <code>apiKey</code>, <code>schedules</code>, <code>reminders</code>, <code>playground</code>, <code>authToken</code> (the <code>--bearer-token</code> equivalent), <code>allowAnonymous</code>, <code>publicUrl</code>, <code>cursorEvents</code>, and <code>mode: "single" | "multi"</code>. The Cursor credential resolves in one order everywhere: explicit <code>apiKey</code>, then <code>CURSOR_API_KEY</code>, then the key stored by <code>agent-sdk login</code>.</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="./instructions.html">Instructions</a>: the required half of a minimal agent</li><li><a href="./../guides/cloud-runtime.html">Cloud runtime</a>: when and how to leave the host</li><li><a href="./cli.html">CLI</a>: the flags <code>ServeOptions</code> mirrors</li></ul>`,
|
|
36
|
+
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// handle.createReminder(...), handle.project, await handle.close()</span></span></code></pre></div><p><code>ServeOptions</code> mirrors the CLI flags: <code>port</code>, <code>host</code>, <code>dev</code>, <code>stateRoot</code>, <code>apiKey</code>, <code>schedules</code>, <code>reminders</code>, <code>noControlPlane</code>, <code>playground</code>, <code>docs</code>, <code>authToken</code> (the <code>--bearer-token</code> equivalent), <code>allowAnonymous</code>, <code>allowAnonymousCursorGithub</code>, <code>allowAnonymousCursorAccountMcp</code>, <code>cursorGithubProxy</code>, <code>publicUrl</code>, <code>cloudToolsUrl</code>, <code>cursorEvents</code>, and <code>logger</code>. <code>serve()</code> additionally accepts <code>discovery</code> (project-loading options) and <code>mode: "single" | "multi"</code>. The Cursor credential resolves in one order everywhere: explicit <code>apiKey</code>, then <code>CURSOR_API_KEY</code>, then the key stored by <code>agent-sdk login</code>.</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="./instructions.html">Instructions</a>: the required half of a minimal agent</li><li><a href="./../guides/cloud-runtime.html">Cloud runtime</a>: when and how to leave the host</li><li><a href="./cli.html">CLI</a>: the flags <code>ServeOptions</code> mirrors</li></ul>`,41)])])}const u=e(n,[["render",o]]);export{k as __pageData,u as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as e,c as i,o as a,ag as t}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically.","frontmatter":{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically."},"headers":[],"relativePath":"reference/agent-config.md","filePath":"reference/agent-config.md"}'),n={name:"reference/agent-config.md"};function o(
|
|
1
|
+
import{_ as e,c as i,o as a,ag as t}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically.","frontmatter":{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically."},"headers":[],"relativePath":"reference/agent-config.md","filePath":"reference/agent-config.md"}'),n={name:"reference/agent-config.md"};function o(d,s,l,r,h,c){return a(),i("div",null,[...s[0]||(s[0]=[t("",41)])])}const u=e(n,[["render",o]]);export{k as __pageData,u as default};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP.","frontmatter":{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP."},"headers":[],"relativePath":"reference/artifacts.md","filePath":"reference/artifacts.md"}'),n={name:"reference/artifacts.md"};function d(o,s,r,l,h,p){return i(),e("div",null,[...s[0]||(s[0]=[t(`<h1 id="artifacts" tabindex="-1">Artifacts <a class="header-anchor" href="#artifacts" aria-label="Permalink to "Artifacts""></a></h1><p>An artifact marks a durable output the agent produced: a reviewed PR URL, a generated report, a decision record. Sessions come and go; artifacts persist across them, capped and listable, so the people supervising an agent see what it shipped without replaying event streams.</p><h2 id="declare-kinds" tabindex="-1">Declare kinds <a class="header-anchor" href="#declare-kinds" aria-label="Permalink to "Declare kinds""></a></h2><p>Author <code>agent/artifacts.ts</code> with <code>defineArtifacts</code> from <code>@cursor/july/artifacts</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;"> { z } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "zod"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
|
2
|
+
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { defineArtifacts } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "@cursor/july/artifacts"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
|
3
|
+
<span class="line"></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;"> defineArtifacts</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
5
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> kinds: {</span></span>
|
|
6
|
+
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "reviewed-pr"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: {</span></span>
|
|
7
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> description: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"A pull request this agent reviewed."</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
8
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> schema: z.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">object</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ url: z.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(), verdict: z.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">() }),</span></span>
|
|
9
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
10
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> report: { description: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"A generated report."</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>
|
|
12
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> agentTool: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
13
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p><code>defineArtifacts</code> accepts three fields. <code>kinds</code> declares the artifact kinds: with kinds declared, <code>tag</code> accepts only these; with none, any kind string is accepted freeform. Each kind's <code>description</code> says what it holds and doubles as the model-facing prompt for <code>tag_artifact</code>. An optional Zod <code>schema</code> validates payloads before they persist (the parsed output is stored, so defaults and coercions apply). <code>agentTool</code> exposes the model-facing <code>tag_artifact</code> tool generated from the kinds registry; it requires at least one declared kind. <code>max</code> is the retention cap, default 1000: on insert past the cap, the oldest-updated artifact is evicted.</p><h2 id="tag-from-host-code" tabindex="-1">Tag from host code <a class="header-anchor" href="#tag-from-host-code" aria-label="Permalink to "Tag from host code""></a></h2><p>Every handler surface carries <code>ctx.artifacts</code> (or <code>args.artifacts</code>), an <code>ArtifactsApi</code> with <code>tag</code> and <code>list</code>: tools, hooks, channel route handlers and <code>onStart</code>, schedule <code>run</code> handlers, and reminder <code>run</code> handlers. Tool and hook facades are session-bound, so <code>tag</code> auto-fills the <code>sessionId</code> (and <code>turnId</code> when known). Channel, schedule, and reminder facades are unbound; pass <code>sessionId</code> in the tag input to attribute one.</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;">await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ctx.artifacts.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">tag</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
|
14
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> kind: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"reviewed-pr"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
15
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> key: prUrl,</span></span>
|
|
16
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> title: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`Reviewed \${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">prUrl</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
|
17
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> data: { url: prUrl, verdict: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"approve"</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><p><code>key</code> is the upsert handle: tagging the same key again replaces the record instead of creating a new one, so re-reviewing a PR updates one row. A <code>contents</code> payload (string or bytes, with an optional <code>contentType</code>) attaches a file or blob served at <code>GET /v1/artifacts/:id/content</code>; re-tagging a keyed artifact without <code>contents</code> keeps the existing payload.</p><h2 id="let-the-model-tag" tabindex="-1">Let the model tag <a class="header-anchor" href="#let-the-model-tag" aria-label="Permalink to "Let the model tag""></a></h2><p>With <code>agentTool: true</code>, the <code>tag_artifact</code> server tool materializes from the kinds registry. Its description tells the model to tag notable outputs and lists each kind with its description, and its input schema is a discriminated union over the declared kinds, so a schema'd kind is validated exactly like a host-side tag. An authored tool named <code>tag_artifact</code> shadows the built-in, with a warning.</p><h2 id="observe-and-list" tabindex="-1">Observe and list <a class="header-anchor" href="#observe-and-list" aria-label="Permalink to "Observe and list""></a></h2><p>Tagging emits an <code>artifact.tagged</code> event on the attributed session's stream, carrying the record: <code>id</code>, <code>kind</code>, <code>key</code>, <code>title</code>, <code>data</code>, and <code>source</code> (<code>"host"</code> for host code, <code>"model"</code> for <code>tag_artifact</code>). Hooks, channel <code>events</code>, and evals see it like any other <a href="./sessions.html#which-events-can-i-stream">stream event</a>.</p><p>Over HTTP:</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;">curl</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'http://127.0.0.1:3000/<slug>/v1/artifacts?kind=reviewed-pr&limit=20'</span></span>
|
|
19
|
+
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">curl</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'http://127.0.0.1:3000/<slug>/v1/artifacts/<id>/content'</span></span></code></pre></div><p><code>GET /v1/artifacts</code> returns records newest-updated first, filterable by <code>kind</code> and <code>sessionId</code>. Session ownership applies, same as <code>/v1/sessions</code>. The playground renders tagged artifacts too.</p><h2 id="gate-evals-on-tagging" tabindex="-1">Gate evals on tagging <a class="header-anchor" href="#gate-evals-on-tagging" aria-label="Permalink to "Gate evals on tagging""></a></h2><p><code>t.taggedArtifact(kind?, predicate?)</code> gates an eval on at least one artifact tagged during the test turn, optionally of one kind and matching a predicate over the record:</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:#24292E;--shiki-dark:#E1E4E8;">t.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">taggedArtifact</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"reviewed-pr"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">record</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;"> record.source </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "model"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</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="./sessions.html">Sessions and streaming</a>: the <code>artifact.tagged</code> event in the full vocabulary</li><li><a href="./tools.html">Tools</a>: the <code>ctx</code> that carries <code>artifacts</code></li><li><a href="./../evals.html">Evals</a>: the assertions <code>taggedArtifact</code> sits beside</li></ul>`,23)])])}const g=a(n,[["render",d]]);export{k 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 k=JSON.parse('{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP.","frontmatter":{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP."},"headers":[],"relativePath":"reference/artifacts.md","filePath":"reference/artifacts.md"}'),n={name:"reference/artifacts.md"};function d(o,s,r,l,h,p){return i(),e("div",null,[...s[0]||(s[0]=[t("",23)])])}const g=a(n,[["render",d]]);export{k as __pageData,g as default};
|
package/dist/docs/assets/{reference_channels.md.CDhTRfUz.js → reference_channels.md.BIabFUAI.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{_ as e,c as a,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const
|
|
1
|
+
import{_ as e,c as a,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies.","frontmatter":{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies."},"headers":[],"relativePath":"reference/channels.md","filePath":"reference/channels.md"}'),n={name:"reference/channels.md"};function h(l,s,o,d,r,p){return i(),a("div",null,[...s[0]||(s[0]=[t(`<h1 id="channels" tabindex="-1">Channels <a class="header-anchor" href="#channels" aria-label="Permalink to "Channels""></a></h1><p>A channel is the surface an agent lives on. The built-in HTTP session channel is always mounted. Custom channels declare their own routes under <code>/v1/channels/<id></code>. The Slack and GitHub packs are prebuilt channels with platform transports. This page is the authoring reference; for the walkthrough, see the <a href="./../guides/webhooks.html">Webhooks guide</a>.</p><h2 id="the-built-in-http-channel" tabindex="-1">The built-in HTTP channel <a class="header-anchor" href="#the-built-in-http-channel" aria-label="Permalink to "The built-in HTTP channel""></a></h2><p>It's always mounted, under <code>/<slug></code> in the default multi-agent layout: session create, follow-up, stream, stop, the sessions list, approvals, deterministic tool calls, health, and info. For the route-by-route contract, see the <a href="./http-api.html">HTTP API reference</a>.</p><p>Author <code>agent/channels/http.ts</code> only to override its defaults:</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;"> {</span></span>
|
|
2
2
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> bearerAuth,</span></span>
|
|
3
3
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> httpChannel,</span></span>
|
|
4
4
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> localDevStrict,</span></span>
|
|
@@ -50,4 +50,4 @@ import{_ as e,c as a,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const c
|
|
|
50
50
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
51
51
|
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
|
|
52
52
|
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // auth: [...], state: {...}, onStart(...), onStop(...)</span></span>
|
|
53
|
-
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>This example assumes <code>agent/tools/inspect_pr.ts</code> exists. The handler calls it before the model turn, so every review starts with validated PR data. It also derives a stable conversation key from the PR URL and writes the tool result to <code>pr.json</code>. Instructions can ask the model to inspect a PR, but host code guarantees it.</p><h2 id="route-verbs-and-schemas" tabindex="-1">Route verbs and schemas <a class="header-anchor" href="#route-verbs-and-schemas" aria-label="Permalink to "Route verbs and schemas""></a></h2><p><code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>PATCH</code>, and <code>DELETE</code> helpers build routes. Their schemas are Zod, enforced at compile time:</p><table tabindex="0"><thead><tr><th>Verb</th><th>Required schema</th></tr></thead><tbody><tr><td><code>GET</code></td><td><code>querySchema</code></td></tr><tr><td><code>POST</code> / <code>PUT</code> / <code>PATCH</code></td><td><code>bodySchema</code> (optional <code>querySchema</code>)</td></tr><tr><td><code>DELETE</code></td><td>both optional</td></tr></tbody></table><p>Plain JSON Schema objects won't type-check; use <code>z.object({})</code> or <code>z.unknown()</code> for intentionally open surfaces. The host validates before the handler runs. Handlers receive typed <code>args.body</code> and <code>args.query</code>, and empty POST bodies are coerced to <code>{}</code> first. Declared schemas are projected on <code>GET /v1/info</code>, which powers the playground's <strong>Try</strong> buttons and composer <strong>slash commands</strong>.</p><h2 id="handler-arguments" tabindex="-1">Handler arguments <a class="header-anchor" href="#handler-arguments" aria-label="Permalink to "Handler arguments""></a></h2><p>Handlers receive the Fetch <code>Request</code> and an args object:</p><table tabindex="0"><thead><tr><th>Member</th><th>What it is</th></tr></thead><tbody><tr><td><code>send(message, options?)</code></td><td>Run a model turn on this channel; returns the session handle. Options: <code>continuationToken</code> (the conversation key), <code>workspaceFiles</code>, <code>workspaceDir</code>, <code>cloud</code> (attach cloud repos for this session), <code>auth</code> (defaults to the request principal), <code>sdkAgentId</code> (resume a specific SDK agent).</td></tr><tr><td><code>getSession(sessionId)</code></td><td>Look up an existing session on this channel</td></tr><tr><td><code>receive(channelDefinition, input)</code></td><td>Hand off to another channel (schedules use this)</td></tr><tr><td><code>callTool(name, input, options?)</code></td><td>Deterministic server-tool call (<a href="./tools.html#call-a-tool-without-a-model-turn">Tools</a>)</td></tr><tr><td><code>body</code>, <code>query</code>, <code>params</code></td><td>Validated payloads and <code>:param</code> path segments</td></tr><tr><td><code>auth</code></td><td>The <code>AuthContext</code> resolved by this route's auth chain</td></tr><tr><td><code>requestIp</code></td><td>The TCP peer address</td></tr><tr><td><code>host</code></td><td>Shared services: <code>host.mcp</code>, <code>host.github</code>, <code>host.slack</code>, <code>host.reminders</code></td></tr><tr><td><code>waitUntil(promise)</code></td><td>Background work that outlives the response</td></tr><tr><td><code>sessionUrls(request, sessionId)</code></td><td>Absolute playground + trace URLs for a session on this mount</td></tr></tbody></table><h2 id="events" tabindex="-1">Events <a class="header-anchor" href="#events" aria-label="Permalink to "Events""></a></h2><p>The <code>events</code> map subscribes the channel to stream events for the sessions it owns. Keys are event types from the <a href="./sessions.html#the-event-vocabulary">event vocabulary</a>, or <code>"*"</code>. Handlers receive <code>(event, channel, ctx)</code>, where <code>channel.state</code> is the per-session adapter state and <code>ctx</code> exposes session info and host services. This is where a channel delivers replies back to its surface.</p><h2 id="state-and-lifecycle" tabindex="-1">State and lifecycle <a class="header-anchor" href="#state-and-lifecycle" aria-label="Permalink to "State and lifecycle""></a></h2><p><code>state</code> declares the starting per-session adapter state (JSON), persisted on the session record. Routes and event handlers read and mutate it through <code>channel.state</code>. <code>onStart(args)</code> runs when the channel mounts. It receives <code>send</code>, <code>receive</code>, <code>callTool</code>, <code>host</code>, and friends; the Slack pack opens its Socket Mode connection here. <code>onStop()</code> runs when the server drains.</p><h2 id="auth-policies" tabindex="-1">Auth policies <a class="header-anchor" href="#auth-policies" aria-label="Permalink to "Auth policies""></a></h2><p>Every route runs an auth-policy chain: the channel's <code>auth</code> array, or <code>[localDevStrict()]</code> when unset. A policy is a function <code>(request, info) => AuthContext | null</code> (async allowed); the first non-null wins, and a request no policy admits gets <code>401</code>.</p><table tabindex="0"><thead><tr><th>Policy</th><th>Admits</th></tr></thead><tbody><tr><td><code>localDevStrict()</code></td><td>Direct loopback callers with no proxy-forwarding headers (<code>X-Forwarded-For</code>, <code>X-Real-IP</code>, <code>Forwarded</code>, and <code>X-Forwarded-Host</code> are all rejected, so tunnels and same-host reverse proxies don't silently re-expose the route), plus a loopback <code>Host</code> header, which rejects DNS-rebinding callers that reach 127.0.0.1 with a remote hostname.</td></tr><tr><td><code>localDev()</code></td><td>Like <code>localDevStrict()</code> but without the <code>Host</code> check. An explicit, weaker opt-in.</td></tr><tr><td><code>loopbackOnly()</code></td><td>A loopback TCP peer, ignoring forwarding headers; for dev relays that legitimately carry them, like <code>gh webhook forward</code>.</td></tr><tr><td><code>bearerAuth(token)</code></td><td><code>Authorization: Bearer <token></code>, compared in constant time. Also accepts a verifier function mapping a presented token to an <code>AuthContext</code>.</td></tr><tr><td><code>allowAll()</code></td><td>Everyone, as an <code>anonymous</code> principal. Only for surfaces protected upstream (an HMAC-verified webhook) or intentionally public.</td></tr></tbody></table><p>The resolved <code>AuthContext</code> (<code>{ authenticator, principalId, principalType, attributes? }</code>) becomes the request principal. Sessions bind to the principal that created them, and follow-up, stream, and list routes enforce ownership (<code>403</code> otherwise).</p><p>Server flags interact with authored auth: <code>--bearer-token</code> swaps the default <code>localDevStrict()</code> for <code>bearerAuth(...)</code> on channels that don't author their own chain, and <code>--allow-anonymous</code> swaps it for <code>allowAll()</code>. Authored <code>auth</code> arrays always win over both. A channel that declares <code>[localDevStrict()]</code> stays loopback-only even on an <code>--allow-anonymous</code> host.</p><h2 id="first-class-channels" tabindex="-1">First class channels <a class="header-anchor" href="#first-class-channels" aria-label="Permalink to "First class channels""></a></h2><p><strong>Slack</strong> (<code>@cursor/july/channels/slack</code>): Socket Mode transport, streaming replies, engagement rules, approval cards, and a default block on Slack Connect / guest / other-workspace senders. Author <code>agent/channels/slack.ts</code> with <code>slackChannel()</code>. Guide: <a href="./../guides/slack.html">Slack</a>.</p><p><strong>GitHub</strong> (<code>@cursor/july/channels/github</code>): webhook dispatch with signature verification, per-event hooks returning <code>{ auth }</code> (a model turn), <code>{ task }</code> (host work), or <code>null</code>, and CLI tooling for replay and live forwarding. Author <code>agent/channels/github.ts</code> with <code>githubChannel()</code>. Guide: <a href="./../guides/github.html">GitHub</a>.</p><p>For other platforms like Discord or Teams, use the authored <code>defineChannel</code> webhook form.</p><h2 id="continuation-semantics" tabindex="-1">Continuation semantics <a class="header-anchor" href="#continuation-semantics" aria-label="Permalink to "Continuation semantics""></a></h2><p>Channels own their continuation-token format. The built-in HTTP channel mints opaque rotating tokens, Slack uses <code>channelId:threadTs</code>, and PR automations use keys like <code>pr:owner/repo#N</code>. Same token, same durable session; one active continuation per session; the HTTP channel returns <code>409</code> for stale tokens. For the full session model, see <a href="./sessions.html">Sessions</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="./../guides/webhooks.html">Webhooks guide</a>: the same API, walked through</li><li><a href="./http-api.html">HTTP API</a>: the built-in routes precisely</li><li><a href="./sessions.html">Sessions and streaming</a>: the events channels subscribe to</li></ul>`,35)])])}const E=e(n,[["render",h]]);export{c as __pageData,E as default};
|
|
53
|
+
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>This example assumes <code>agent/tools/inspect_pr.ts</code> exists. The handler calls it before the model turn, so every review starts with validated PR data. It also derives a stable conversation key from the PR URL and writes the tool result to <code>pr.json</code>. Instructions can ask the model to inspect a PR, but host code guarantees it.</p><h2 id="route-verbs-and-schemas" tabindex="-1">Route verbs and schemas <a class="header-anchor" href="#route-verbs-and-schemas" aria-label="Permalink to "Route verbs and schemas""></a></h2><p><code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>PATCH</code>, and <code>DELETE</code> helpers build routes. Their schemas are Zod, enforced at compile time:</p><table tabindex="0"><thead><tr><th>Verb</th><th>Required schema</th></tr></thead><tbody><tr><td><code>GET</code></td><td><code>querySchema</code></td></tr><tr><td><code>POST</code> / <code>PUT</code> / <code>PATCH</code></td><td><code>bodySchema</code> (optional <code>querySchema</code>)</td></tr><tr><td><code>DELETE</code></td><td>both optional</td></tr></tbody></table><p>Plain JSON Schema objects won't type-check; use <code>z.object({})</code> or <code>z.unknown()</code> for intentionally open surfaces. The host validates before the handler runs. Handlers receive typed <code>args.body</code> and <code>args.query</code>, and empty POST bodies are coerced to <code>{}</code> first. Declared schemas are projected on <code>GET /v1/info</code>, which powers the playground's <strong>Try</strong> buttons and composer <strong>slash commands</strong>.</p><h2 id="handler-arguments" tabindex="-1">Handler arguments <a class="header-anchor" href="#handler-arguments" aria-label="Permalink to "Handler arguments""></a></h2><p>Handlers receive the Fetch <code>Request</code> and an args object:</p><table tabindex="0"><thead><tr><th>Member</th><th>What it is</th></tr></thead><tbody><tr><td><code>send(message, options?)</code></td><td>Run a model turn on this channel; returns the session handle (options below)</td></tr><tr><td><code>getSession(sessionId)</code></td><td>Look up an existing session on this channel</td></tr><tr><td><code>receive(channelDefinition, input)</code></td><td>Hand off to another channel (schedules use this)</td></tr><tr><td><code>callTool(name, input, options?)</code></td><td>Deterministic server-tool call (<a href="./tools.html#call-a-tool-without-a-model-turn">Tools</a>)</td></tr><tr><td><code>body</code>, <code>query</code>, <code>params</code></td><td>Validated payloads and <code>:param</code> path segments</td></tr><tr><td><code>auth</code></td><td>The <code>AuthContext</code> resolved by this route's auth chain</td></tr><tr><td><code>requestIp</code></td><td>The TCP peer address</td></tr><tr><td><code>host</code></td><td>Shared services: <code>host.mcp</code>, <code>host.github</code>, <code>host.slack</code>, <code>host.kv</code>, <code>host.files</code>, <code>host.reminders</code></td></tr><tr><td><code>waitUntil(promise)</code></td><td>Background work that outlives the response</td></tr><tr><td><code>sessionUrls(request, sessionId)</code></td><td>Absolute playground + trace URLs for a session on this mount</td></tr><tr><td><code>artifacts</code></td><td>Unbound <a href="./artifacts.html">artifacts</a> facade; pass <code>sessionId</code> in <code>tag</code> input to attribute one</td></tr></tbody></table><p><code>send</code> options: <code>continuationToken</code> (the conversation key), <code>admission</code> (<code>"preempt"</code> interrupts a busy session, the default; <code>"coalesce"</code> enqueues behind the running turn, the <a href="./sessions.html#what-happens-when-i-send-a-follow-up">Slack policy</a>), <code>workspaceFiles</code>, <code>workspaceDir</code>, <code>cloud</code> (attach cloud repos for this session), <code>auth</code> (defaults to the request principal), <code>sdkAgentId</code> (resume a specific SDK agent), <code>state</code> (starting channel state for new sessions), <code>title</code> (session display title), <code>purpose</code> (<code>"eval"</code> skips sticky A/B enrollment), and <code>coalesceSourceTs</code> (dedupe key for coalesce queue items already delivered mid-turn).</p><h2 id="events" tabindex="-1">Events <a class="header-anchor" href="#events" aria-label="Permalink to "Events""></a></h2><p>The <code>events</code> map subscribes the channel to stream events for the sessions it owns. Keys are event types from the <a href="./sessions.html#which-events-can-i-stream">event vocabulary</a>, or <code>"*"</code>. Handlers receive <code>(event, channel, ctx)</code>, where <code>channel.state</code> is the per-session adapter state and <code>ctx</code> exposes session info and host services. This is where a channel delivers replies back to its surface.</p><h2 id="state-and-lifecycle" tabindex="-1">State and lifecycle <a class="header-anchor" href="#state-and-lifecycle" aria-label="Permalink to "State and lifecycle""></a></h2><p><code>state</code> declares the starting per-session adapter state (JSON), persisted on the session record. Routes and event handlers read and mutate it through <code>channel.state</code>. <code>onStart(args)</code> runs when the channel mounts; the Slack pack opens its Socket Mode connection here. <code>onStop()</code> runs when the server drains.</p><p><code>onStart</code> receives the route helpers (<code>send</code>, <code>getSession</code>, <code>receive</code>, <code>callTool</code>, <code>host</code>, <code>waitUntil</code>, <code>artifacts</code>, and a <code>logger</code> that respects the server's log sink) plus a set that exists for long-lived transports:</p><ul><li><code>emitAssistantMessage(sessionId, text)</code> appends an assistant message without a model turn, for host tasks that already produced the final text.</li><li><code>hasContinuationSession(token)</code> and <code>isContinuationBusy(token)</code> report whether a continuation token has a live session and whether a turn is in flight on it.</li><li><code>getContinuationLastBotMessageTs(token)</code> reads the Slack warm-delta watermark from channel state.</li><li><code>interruptContinuation(token)</code> stops the in-flight turn and clears coalesced follow-ups queued behind it.</li><li><code>resolveApproval(sessionId, callId, decision, auth, options?)</code> approves or denies a parked tool call, how Slack Block Kit buttons unblock a turn without the HTTP approvals route.</li></ul><h2 id="auth-policies" tabindex="-1">Auth policies <a class="header-anchor" href="#auth-policies" aria-label="Permalink to "Auth policies""></a></h2><p>Every route runs an auth-policy chain: the channel's <code>auth</code> array, or <code>[localDevStrict()]</code> when unset. A policy is a function <code>(request, info) => AuthContext | null</code> (async allowed); the first non-null wins, and a request no policy admits gets <code>401</code>.</p><table tabindex="0"><thead><tr><th>Policy</th><th>Admits</th></tr></thead><tbody><tr><td><code>localDevStrict()</code></td><td>Direct loopback callers with no proxy-forwarding headers (<code>X-Forwarded-For</code>, <code>X-Real-IP</code>, <code>Forwarded</code>, and <code>X-Forwarded-Host</code> are all rejected, so tunnels and same-host reverse proxies don't silently re-expose the route), plus a loopback <code>Host</code> header, which rejects DNS-rebinding callers that reach 127.0.0.1 with a remote hostname.</td></tr><tr><td><code>localDev()</code></td><td>Like <code>localDevStrict()</code> but without the <code>Host</code> check. An explicit, weaker opt-in.</td></tr><tr><td><code>loopbackOnly()</code></td><td>A loopback TCP peer, ignoring forwarding headers; for dev relays that legitimately carry them, like <code>gh webhook forward</code>.</td></tr><tr><td><code>bearerAuth(token)</code></td><td><code>Authorization: Bearer <token></code>, compared in constant time. Also accepts a verifier function mapping a presented token to an <code>AuthContext</code>.</td></tr><tr><td><code>allowAll()</code></td><td>Everyone, as an <code>anonymous</code> principal. Only for surfaces protected upstream (an HMAC-verified webhook) or intentionally public.</td></tr></tbody></table><p>The resolved <code>AuthContext</code> (<code>{ authenticator, principalId, principalType, attributes? }</code>) becomes the request principal. Sessions bind to the principal that created them, and follow-up, stream, and list routes enforce ownership (<code>403</code> otherwise).</p><p>Server flags interact with authored auth: <code>--bearer-token</code> swaps the default <code>localDevStrict()</code> for <code>bearerAuth(...)</code> on channels that don't author their own chain, and <code>--allow-anonymous</code> swaps it for <code>allowAll()</code>. Authored <code>auth</code> arrays always win over both. A channel that declares <code>[localDevStrict()]</code> stays loopback-only even on an <code>--allow-anonymous</code> host.</p><h2 id="first-class-channels" tabindex="-1">First class channels <a class="header-anchor" href="#first-class-channels" aria-label="Permalink to "First class channels""></a></h2><p><strong>Slack</strong> (<code>@cursor/july/channels/slack</code>): Socket Mode transport, streaming replies, engagement rules, approval cards, and a default block on Slack Connect / guest / other-workspace senders. Author <code>agent/channels/slack.ts</code> with <code>slackChannel()</code>. Guide: <a href="./../guides/slack.html">Slack</a>.</p><p><strong>GitHub</strong> (<code>@cursor/july/channels/github</code>): webhook dispatch with signature verification, per-event hooks returning <code>{ auth }</code> (a model turn), <code>{ task }</code> (host work), or <code>null</code>, and CLI tooling for replay and live forwarding. Author <code>agent/channels/github.ts</code> with <code>githubChannel()</code>. Guide: <a href="./../guides/github.html">GitHub</a>.</p><p>For other platforms like Discord or Teams, use the authored <code>defineChannel</code> webhook form.</p><h2 id="continuation-semantics" tabindex="-1">Continuation semantics <a class="header-anchor" href="#continuation-semantics" aria-label="Permalink to "Continuation semantics""></a></h2><p>Channels own their continuation-token format. The built-in HTTP channel mints opaque rotating tokens, Slack uses <code>channelId:threadTs</code>, and PR automations use keys like <code>pr:owner/repo#N</code>. Same token, same durable session; one active continuation per session; the HTTP channel returns <code>409</code> for stale tokens. For the full session model, see <a href="./sessions.html">Sessions</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="./../guides/webhooks.html">Webhooks guide</a>: the same API, walked through</li><li><a href="./http-api.html">HTTP API</a>: the built-in routes precisely</li><li><a href="./sessions.html">Sessions and streaming</a>: the events channels subscribe to</li></ul>`,38)])])}const E=e(n,[["render",h]]);export{k as __pageData,E as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as e,c as a,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const
|
|
1
|
+
import{_ as e,c as a,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies.","frontmatter":{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies."},"headers":[],"relativePath":"reference/channels.md","filePath":"reference/channels.md"}'),n={name:"reference/channels.md"};function h(l,s,o,d,r,p){return i(),a("div",null,[...s[0]||(s[0]=[t("",38)])])}const E=e(n,[["render",h]]);export{k as __pageData,E as default};
|