Skip to content

Agent config (agent/agent.ts)

agent/agent.ts default-exports defineAgent(config): which model runs the agent, where turns execute, and runtime-specific defaults. Everything is optional on the root agent.

ts
import { defineAgent } from "@cursor/july";

export default defineAgent({
  model: {
    id: "grok-4.5",
    params: [
      { id: "effort", value: "high" },
      { id: "fast", value: "true" },
    ],
  }, // optional; this is the default
  runtime: "local", // default, or "cloud"
  // cloud: {
  //   repos: [{ url: "https://github.com/org/repo", startingRef: "main" }],
  // },
  // local: { cwd: "../harness" },
});

Fields on defineAgent

defineAgent accepts these fields.

FieldTypeMeaning
modelstring or { id, params }Cursor model for turns. Defaults to grok-4.5 with effort=high, fast=true on the root agent. Subagents omit it to inherit.
namestringDisplay name override. Defaults to the package name or directory name.
descriptionstringWhat the agent is for. Required on subagents; the parent model reads it to decide when to delegate. Documentation-only on the root.
instructionsstringInline instructions. Prefer instructions.md; this exists for subagents and generated configs.
runtime"local" or "cloud"Where turns execute. Default "local".
cloudobjectCloud agent defaults: repos, env, envVars, forwarded to the Cursor SDK. Used when runtime is "cloud", and as the base merged under per-session cloud send options.
local{ cwd?, workspaceDir?, sandbox? }Local harness defaults; ignored for cloud turns. See Local options.
hosting{ egressDomains?, secretNames? }Managed-hosting declarations read by agent-sdk deploy: the pod's egress allowlist and the secret names the agent expects. Ignored by local serving.
concurrency{ maxRunningTurns? }Engine-wide turn admission limit. See Concurrency.
builtinTools{ reminders? }Framework-provided model-facing tools, opted in per capability. See Built-in tools.
toolsToolName[]Allowlist of built-in harness tools offered to the model. Unset = the model's full standard toolset. See Allowlist built-in harness tools.

Choose a model

model is a Cursor model id string, or { id, params }. Effort and speed are params, not id suffixes. The SDK rejects suffix-style ids like grok-4.5-fast:

ts
model: {
  id: "grok-4.5",
  params: [
    { id: "effort", value: "high" },
    { id: "fast", value: "true" },
  ],
}

A plain string works when you don't need params:

ts
model: "composer-2.5",

Choose a runtime

runtime: "local" (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.

runtime: "cloud" runs turns on Cursor cloud agents (bc-… ids). Pass a cloud block with the repos the VM carries. Server tools stay reachable over authenticated HTTP MCP back to the serve host when --public-url or --cloud-tools-url 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.

validate warns when runtime: "cloud" is combined with agent tools, skills, or sandbox seeds, which only materialize into local session workspaces, and when the cloud block is missing. The full capability matrix and the patterns that hold up are in the Cloud runtime guide.

Local options

local sets local-harness defaults, all ignored for cloud turns.

local.workspaceDir points every session at one shared harness cwd, for agents that work inside an existing checkout. It takes precedence over cwd, and a per-send workspaceDir 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.

local.sandbox 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.

Local cwd

local.cwd sets the default parent directory for local harness workspaces. Each session uses <cwd>/<sessionId> (absolute, or relative to the project root) unless a per-send workspaceDir overrides it.

This is your control over ambient context. Session workspaces are real Cursor project directories, so the harness loads AGENTS.md and .cursor config from ancestor directories. An agent inside a big monorepo that must not inherit the monorepo's rules points cwd outside it (or runs with --state-root under /tmp). An agent that needs a specific checkout's skills and rules points cwd inside that checkout.

Allowlist built-in harness tools

Use tools to limit which built-in Cursor harness tools the model can call. Omit it to keep the standard toolset. When you set it, the model gets only the tools you list. An empty list disables all native built-in tools. Because this field is an allowlist, new platform tools stay disabled until you add them.

ts
export default defineAgent({
  model: "composer-2.5",
  // Read-only triage agent: search and read only.
  // No shell, no edits, no subagents.
  tools: ["read", "grep", "glob", "ls"],
});

Agent Serve always adds "mcp" to a configured allowlist. Authored server tools in agent/tools/ use MCP to reach the model. MCP can also expose declared connections and servers from the harness directory's ambient .cursor config. To exclude a checkout's MCP servers, point local.cwd outside the checkout. See Local cwd. local.sandbox makes MCP tool calls fail closed.

Use the SDK's public tool names, including "shell", "read", "edit", "grep", "glob", "ls", and "task". Unknown names fail the turn with a ConfigurationError.

Two names have broader effects:

  • "shell" also grants shell input. Tools with execution: "agent" need it to run their scripts. Discovery warns when your allowlist would prevent those tools from running.
  • "task" lets the root agent start subagents. Each subagent keeps its own curated toolset.

Tool allowlists work only with the local runtime. A runtime: "cloud" agent that sets tools fails at serve startup. Agent Serve also refuses per-send cloud sessions from a hybrid agent with an allowlist. It won't run those sessions with unrestricted tool access.

The allowlist controls which tools the model can call. It does not isolate the serve host. For agents that process untrusted input, also set local: { sandbox: true }.

The cloud block

Cloud agent defaults forwarded to the Cursor SDK: repos (each { url, startingRef? }), environment selection, envVars, 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 Cloud runtime.

Concurrency

concurrency.maxRunningTurns 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 turn.queued event with the queue position, GET /v1/sessions reports queued: true, 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 409 session_busy. Omit for unlimited.

ts
export default defineAgent({
  concurrency: { maxRunningTurns: 3 },
});

Built-in tools

builtinTools opts into framework-provided model-facing tools. Each enabled capability materializes as ordinary server tools at discovery time, so turns, direct calls, info, 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.

builtinTools: { reminders: true } adds three tools bound to the current conversation over host.reminders: reminders_create, reminders_list, and reminders_cancel. Sessions without a continuation key can't arm reminders. See Schedules and reminders.

Generate instructions

When the system prompt must be computed, author agent/instructions.ts instead of markdown:

ts
import { defineInstructions } from "@cursor/july";

export default defineInstructions({
  markdown: `You are the on-call assistant for ${process.env.TEAM_NAME}.`,
});

The directory form and the runtime mapping are in Instructions.

Serve programmatically

serve(dirOrProject, options) embeds the server in your own process:

ts
import { serve } from "@cursor/july";

const handle = await serve("./my-agent", {
  port: 3000,
  apiKey: process.env.CURSOR_API_KEY, // optional; see credential order
});
console.log(`listening on ${handle.url}`);
// handle.callTool(...), handle.dispatchSchedule("heartbeat"),
// handle.createReminder(...), handle.project, await handle.close()

ServeOptions mirrors the CLI flags: port, host, dev, stateRoot, apiKey, schedules, reminders, noControlPlane, playground, docs, authToken (the --bearer-token equivalent), allowAnonymous, allowAnonymousCursorGithub, allowAnonymousCursorAccountMcp, cursorGithubProxy, publicUrl, cloudToolsUrl, cursorEvents, and logger. serve() additionally accepts discovery (project-loading options) and mode: "single" | "multi". The Cursor credential resolves in one order everywhere: explicit apiKey, then CURSOR_API_KEY, then the key stored by agent-sdk login.

What's next

Continue with these pages: