Skip to content

AGENTS.md

203 lines · 6.7 KB · Markdown
Raw

@kentcdodds/cursor — agent notes

Human setup and intent live in README.md. This file is for agents: imports, smoke checks, snippets, and edge cases. Secrets by name only — never paste key values. Do not disable live webhooks or jobs.

Secrets

NameScopeRequiredNotes
cursorApiKeyuserYesRaw key from cursor.com/dashboard → API Keys
githubPersonalAccessTokenuserNoOnly for agentsWithOpenGithubPrs

Host: api.cursor.com. Placeholder: {{secret:cursorApiKey}}.

Import paths

ExportImport
overviewkody:@kentcdodds/cursor
request (cursorRequest)kody:@kentcdodds/cursor/request
agentskody:@kentcdodds/cursor/agents
runskody:@kentcdodds/cursor/runs
artifactskody:@kentcdodds/cursor/artifacts
workerskody:@kentcdodds/cursor/workers
modelskody:@kentcdodds/cursor/models
repositorieskody:@kentcdodds/cursor/repositories
me (apiKeyInfo)kody:@kentcdodds/cursor/me
agent-usage (getAgentUsage)kody:@kentcdodds/cursor/agent-usage

Prefer static kody:@kentcdodds/cursor/... imports from execute. Do not lead with packages.invoke.

Defaults: ./request → cursorRequest; ./agents → listAgents; ./runs → listRuns; ./artifacts → listArtifacts; ./workers → getFleetSummary; ./models → listModels; ./repositories → listRepositories; ./me → apiKeyInfo; ./agent-usage → getAgentUsage.

Smoke test (read-only)

import { apiKeyInfo } from 'kody:@kentcdodds/cursor/me'

export default async function main() {
	return await apiKeyInfo()
	// => { apiKeyName, userEmail, ... }
}

Optional read-only follow-ups: listModels() from ./models, or listAgents({ limit: 5 }) from ./agents.

Hand a file to a Cursor cloud agent

Prefer @kentcdodds/agent-files as the durable handoff pipe. Mint a short-lived R2 PUT URL with a tiny MCP execute call, PUT the bytes outside MCP (curl/fetch), then put downloadUrl in the cloud agent prompt so it can curl/download on the VM.

Do not rely on CloudAgent / chat image attachments for usable bytes on the VM — prompt.images is vision-only. Dropbox is an optional secondary when the file should live in Dropbox; agent-files is the default for agent↔agent binary handoffs.

1) Mint upload target (execute)
import createUpload from 'kody:@kentcdodds/agent-files/create-upload'

export default async function main() {
	return await createUpload({
		filename: 'report.png',
		contentType: 'image/png',
		confirm: true,
	})
	// => { key, upload: { method, url, headers }, downloadUrl, expiresAt }
}
2) PUT bytes (outside MCP)
# Use every header from upload.headers; body is the raw file.
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: image/png" \
  # plus remaining keys from target.upload.headers \
  --data-binary @./report.png

Or in one shot after minting:

const target = await createUpload({ filename: 'report.png', contentType: 'image/png', confirm: true })
await fetch(target.upload.url, {
	method: 'PUT',
	headers: target.upload.headers,
	body: fileBytes, // ArrayBuffer / Blob / Uint8Array
})
// hand target.downloadUrl to createAgent / createRun
3) Include downloadUrl in createAgent / createRun prompt
import createUpload from 'kody:@kentcdodds/agent-files/create-upload'
import { createAgent } from 'kody:@kentcdodds/cursor/agents'
import { createRun } from 'kody:@kentcdodds/cursor/runs'

export default async function main() {
	const target = await createUpload({
		filename: 'fixture.zip',
		contentType: 'application/zip',
		confirm: true,
	})
	// PUT fileBytes to target.upload.url with target.upload.headers first…

	const { agent } = await createAgent({
		prompt: {
			text: [
				'Download the fixture and unzip it into ./fixtures before editing.',
				`curl -fsSL '${target.downloadUrl}' -o /tmp/fixture.zip`,
				'unzip -o /tmp/fixture.zip -d ./fixtures',
			].join('\n'),
			// images: [...]  // vision-only; not a byte handoff
		},
		repository: 'https://github.com/your-org/your-repo',
		ref: 'main',
	})

	const { run } = await createRun({
		agentId: agent.id,
		prompt: `Also fetch the same fixture again if needed: ${target.downloadUrl}`,
	})
	return { agentId: agent.id, runId: run.id, downloadUrl: target.downloadUrl }
}

Common snippets

Create agent + follow-up run:

import { createAgent } from 'kody:@kentcdodds/cursor/agents'
import { createRun } from 'kody:@kentcdodds/cursor/runs'

export default async function main() {
	const { agent } = await createAgent({
		prompt: 'Add a README with setup instructions',
		repository: 'https://github.com/your-org/your-repo',
		ref: 'main',
	})
	const { run } = await createRun({
		agentId: agent.id,
		prompt: 'Also add a troubleshooting section',
	})
	return { agentId: agent.id, runId: run.id }
}

Billed usage (do not estimate dollars from token counts):

import { getAgentUsage } from 'kody:@kentcdodds/cursor/agent-usage'

export default async function main() {
	return await getAgentUsage({ agentId: 'bc-…' })
	// cost.rawUsd / cost.chargedUsd from API cost record; chargedCents === 0 → plan-included
}

Raw escape hatch:

import { cursorRequest } from 'kody:@kentcdodds/cursor/request'

export default async function main() {
	return await cursorRequest({ path: '/v1/models' })
}

Pull requests

  • createAgent always enables ManagePullRequest tools. If you create via raw cursorRequest, send autoCreatePR: true so those tools are available.
  • When the cloud agent's task results in code changes, the agent itself must push its branch and create/update the PR via Cursor Cloud's ManagePullRequest before finishing. Do not have Kody, a Kody workflow, or Kody's GitHub integration open the PR as a substitute.
  • The PR must be authored by the Kent C. Dodds Cursor/GitHub account so the standard AI reviewer is triggered.
  • Include this PR-authorship requirement explicitly in every agent creation prompt when spawning via this package.

Edge cases

  • Prefer this package to launch Cursor Cloud agents. Unless the user requests another model, resolve the current latest Grok id with listModels — do not default to Fable or GPT.
  • listRepositories is rate-limited (about 1/min, 30/hour) and may be slow.
  • Workers (./workers) need a pool service-account key path Cursor exposes; ordinary Cloud Agent flows do not.
  • Enterprise Admin / Analytics / AI-Code-Tracking / Bugbot: use ./request, not typed helpers.
  • Never paste cursorApiKey or GitHub token values into chat or logs.
  • File handoffs: use @kentcdodds/agent-files createUpload → PUT → put downloadUrl in prompt text. Do not treat prompt.images as VM bytes.