# Cursor > Send an additional instruction to a running background agent. --- # Source: https://docs.cursor.com/en/background-agent/api/add-followup.md # Add Follow-up > Send an additional instruction to a running background agent. ## OpenAPI ````yaml en/background-agent/api/openapi.yaml post /v0/agents/{id}/followup paths: path: /v0/agents/{id}/followup method: post servers: - url: https://api.cursor.com description: Production server request: security: - title: bearerAuth parameters: query: {} header: Authorization: type: http scheme: bearer description: API key from Cursor Dashboard cookie: {} parameters: path: id: schema: - type: string required: true description: Unique identifier for the background agent example: bc_abc123 query: {} header: {} cookie: {} body: application/json: schemaArray: - type: object properties: prompt: allOf: - type: object required: - text properties: text: type: string minLength: 1 description: The followup instruction for the agent example: Also add a section about troubleshooting images: type: array maxItems: 5 items: $ref: '#/components/schemas/Image' description: Optional array of base64 encoded images (max 5) example: - data: iVBORw0KGgoAAAANSUhEUgAA... dimension: width: 1024 height: 768 required: true requiredProperties: - prompt examples: example: value: prompt: text: Also add a section about troubleshooting images: - data: iVBORw0KGgoAAAANSUhEUgAA... dimension: width: 1024 height: 768 response: '200': application/json: schemaArray: - type: object properties: id: allOf: - type: string description: Unique identifier for the background agent example: bc_abc123 requiredProperties: - id examples: example: value: id: bc_abc123 description: Followup added successfully '400': application/json: schemaArray: - type: object properties: error: allOf: - &ref_0 type: object properties: message: type: string description: Human-readable error message code: type: string description: Machine-readable error code refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Invalid request - bad agent ID format or invalid request body '401': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Unauthorized - invalid or missing API key '403': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Forbidden - insufficient permissions '404': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Agent not found or access denied '409': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Conflict - agent is deleted or archived '429': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Rate limit exceeded '500': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Internal server error deprecated: false type: path components: schemas: ImageDimension: type: object required: - width - height properties: width: type: integer minimum: 1 description: Width must be a positive integer height: type: integer minimum: 1 description: Height must be a positive integer Image: type: object required: - data properties: data: type: string minLength: 1 description: Base64 encoded image data example: iVBORw0KGgoAAAANSUhEUgAA... dimension: $ref: '#/components/schemas/ImageDimension' ```` --- # Source: https://docs.cursor.com/en/background-agent/api/agent-conversation.md # Agent Conversation > Retrieve the conversation history of a background agent. ## OpenAPI ````yaml en/background-agent/api/openapi.yaml get /v0/agents/{id}/conversation paths: path: /v0/agents/{id}/conversation method: get servers: - url: https://api.cursor.com description: Production server request: security: - title: bearerAuth parameters: query: {} header: Authorization: type: http scheme: bearer description: API key from Cursor Dashboard cookie: {} parameters: path: id: schema: - type: string required: true description: Unique identifier for the background agent example: bc_abc123 query: {} header: {} cookie: {} body: {} response: '200': application/json: schemaArray: - type: object properties: id: allOf: - type: string description: Unique identifier for the background agent example: bc_abc123 messages: allOf: - type: array description: Array of conversation messages ordered chronologically items: type: object required: - id - type - text properties: id: type: string description: Unique identifier for the message example: msg_123 type: type: string enum: - user_message - assistant_message description: Type of message - either from the user or the model example: user_message text: type: string description: The content of the message example: Add a README.md file with installation instructions requiredProperties: - id - messages examples: example: value: id: bc_abc123 messages: - id: msg_123 type: user_message text: Add a README.md file with installation instructions description: Conversation retrieved successfully '400': application/json: schemaArray: - type: object properties: error: allOf: - &ref_0 type: object properties: message: type: string description: Human-readable error message code: type: string description: Machine-readable error code refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Invalid request - bad agent ID format '401': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Unauthorized - invalid or missing API key '403': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Forbidden - insufficient permissions '404': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Agent not found or access denied '409': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Conflict - agent is deleted or archived '429': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Rate limit exceeded '500': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Internal server error deprecated: false type: path components: schemas: {} ```` --- # Source: https://docs.cursor.com/en/account/agent-security.md # Agent Security > Security considerations for using Cursor Agent Prompt injection, AI hallucinations, and other issues may cause AI to behave in unexpected and potentially malicious ways. While we continue to work on solving prompt injection at a more foundational level, our primary protection in Cursor products are guardrails around what an agent can do, including requiring manual approval for sensitive actions by default. The goal of this document is to explain our guardrails and what users can expect from them. All of the controls and behavior below are our default and recommended settings. ## First-party tool calls Cursor comes bundled with tools that enable the agent to help our users write code. These include file read, edits, calling terminal commands, searching the web for documentation, and others. Read tools do not require approval (ie reading files, searching across code). Users may use [.cursorignore](/en/context/ignore-files) to block the agent from accessing specific files at all, but otherwise reads are generally permitted without approval. For actions that carry risk of exfiltrating sensitive data, we require explicit approval. Modifying files within the current workspace does not require explicit approval with some exceptions. When an agent makes changes to files they are immediately saved to disk. We recommend that Cursor be run in version controlled workspaces, so that the contents of the files can be reverted at any time. We require explicit approval before changing files that modify the configuration of our IDE/CLI, such as the workspace settings file of the editor. However, users automatically reloading on file change should be aware that agent changes to files may trigger automatic execution before they have had a chance to review the changes. Any terminal command suggested by Agents requires approval by default. We recommend that users review every command before the agent executes it. Users who accept the risk may choose to enable the agent to run all commands without approval. We include an [allowlist](/en/agent/tools) feature in Cursor, but do not consider it to be a security control. Some users choose to allow specific commands, but this is a best effort system and bypasses may be possible. We do not recommend "Run Everything", which bypasses any configured allowlists. ## Third-party tool calls Cursor enables connecting external tools via [MCP](/en/context/mcp). All third party MCP connections must be explicitly approved by the user. Once a user approves an MCP, by default each tool call suggested in Agent Mode for every external MCP integration must be explicitly approved prior to execution. ## Network requests Network requests may be used by an attacker to exfiltrate data. We presently do not support any first-party tools making network requests outside of a very select set of hosts (ie Github), explicit link retrieval, and to support web search with a select set of providers. Arbitrary agent network requests are prevented with default settings. ## Workspace trust The Cursor IDE supports the standard [workspace trust](https://code.visualstudio.com/docs/editing/workspaces/workspace-trust) feature that is *disabled* by default. Workspace trust presents users with a prompt when they open a new workspace to choose normal or restricted mode. Restricted mode breaks AI and other features our users typically use Cursor for. We recommend other tools, such as a basic text editor for working with repos that you do not trust. Workspace trust may be enabled in a users' settings by performing these steps: 1. Open your user settings.json file 2. Add the following configuration: ```json theme={null} "security.workspace.trust.enabled": true ``` This setting can also be enforced organization-wide through Mobile Device Management (MDM) solutions. ## Responsible disclosure If you believe you have found a vulnerability in Cursor, please follow the guide on our GitHub Security page and submit the report there. If you're unable to use GitHub, you may also reach us at [security@cursor.com](mailto:security@cursor.com). We commit to acknowledging vulnerability reports within 5 business days, and addressing them as soon as we are able to. We will publish the results in the form of security advisories on our GitHub security page. Critical incidents will be communicated both on the GitHub security page and via email to all users. --- # Source: https://docs.cursor.com/en/background-agent/api/agent-status.md # Agent Status > Get the current status and results of a specific background agent. ## OpenAPI ````yaml en/background-agent/api/openapi.yaml get /v0/agents/{id} paths: path: /v0/agents/{id} method: get servers: - url: https://api.cursor.com description: Production server request: security: - title: bearerAuth parameters: query: {} header: Authorization: type: http scheme: bearer description: API key from Cursor Dashboard cookie: {} parameters: path: id: schema: - type: string required: true description: Unique identifier for the background agent example: bc_abc123 query: {} header: {} cookie: {} body: {} response: '200': application/json: schemaArray: - type: object properties: id: allOf: - type: string description: Unique identifier for the background agent example: bc_abc123 name: allOf: - type: string description: Name for the agent example: Add README Documentation status: allOf: - type: string enum: - RUNNING - FINISHED - ERROR - CREATING - EXPIRED description: Current status of the background agent example: RUNNING source: allOf: - type: object properties: repository: type: string description: The GitHub repository URL example: https://github.com/your-org/your-repo ref: type: string description: Git ref (branch/tag) used as the base branch example: main target: allOf: - type: object required: - url properties: branchName: type: string description: The Git branch name where the agent is working example: cursor/add-readme-1234 url: type: string description: URL to view the agent in Cursor Web example: https://cursor.com/agents?id=bc_abc123 prUrl: type: string description: URL to view the pull request in GitHub, if any example: https://github.com/your-org/your-repo/pull/1234 autoCreatePr: type: boolean description: Whether a pull request will be automatically created example: false summary: allOf: - type: string description: Summary of the agent's work example: >- Added README.md with installation instructions and usage examples createdAt: allOf: - type: string format: date-time description: When the agent was created example: '2024-01-15T10:30:00Z' requiredProperties: - id - name - status - source - target - createdAt examples: example: value: id: bc_abc123 name: Add README Documentation status: RUNNING source: repository: https://github.com/your-org/your-repo ref: main target: branchName: cursor/add-readme-1234 url: https://cursor.com/agents?id=bc_abc123 prUrl: https://github.com/your-org/your-repo/pull/1234 autoCreatePr: false summary: >- Added README.md with installation instructions and usage examples createdAt: '2024-01-15T10:30:00Z' description: Agent details retrieved successfully '400': application/json: schemaArray: - type: object properties: error: allOf: - &ref_0 type: object properties: message: type: string description: Human-readable error message code: type: string description: Machine-readable error code refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Invalid request - bad agent ID format '401': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Unauthorized - invalid or missing API key '403': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Forbidden - insufficient permissions '404': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Agent not found or access denied '429': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Rate limit exceeded '500': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Internal server error deprecated: false type: path components: schemas: {} ```` --- # Source: https://docs.cursor.com/en/account/teams/analyticsV2.md # Analytics V2 > Advanced team usage and activity metrics tracking We are working on a V2 release of our analytics infrastructure. This includes a refactor of the way in which we track various metrics. As of **September 1, 2025**, and for users on **Cursor version 1.5**, analytics will utilize our V2 infrastructure. Prior versions would have undercounted various metrics, including: * Total Accepted Lines of Code * Total Suggested Lines of Code * Total Tabs Accepted Please stay tuned as we continue to invest in analytics and release new features in this space. --- # Source: https://docs.cursor.com/en/background-agent/api/api-key-info.md # API Key Info > Retrieve metadata about the API key used for authentication. ## OpenAPI ````yaml en/background-agent/api/openapi.yaml get /v0/me paths: path: /v0/me method: get servers: - url: https://api.cursor.com description: Production server request: security: - title: bearerAuth parameters: query: {} header: Authorization: type: http scheme: bearer description: API key from Cursor Dashboard cookie: {} parameters: path: {} query: {} header: {} cookie: {} body: {} response: '200': application/json: schemaArray: - type: object properties: apiKeyName: allOf: - type: string description: The name of the API key example: Production API Key createdAt: allOf: - type: string format: date-time description: When the API key was created example: '2024-01-15T10:30:00Z' userEmail: allOf: - type: string format: email description: >- Email address of the user who owns the API key (if available) example: developer@example.com requiredProperties: - apiKeyName - createdAt examples: example: value: apiKeyName: Production API Key createdAt: '2024-01-15T10:30:00Z' userEmail: developer@example.com description: API key information retrieved successfully '401': application/json: schemaArray: - type: object properties: error: allOf: - &ref_0 type: object properties: message: type: string description: Human-readable error message code: type: string description: Machine-readable error code refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Unauthorized - invalid or missing API key '404': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: API key not found '429': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Rate limit exceeded '500': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Internal server error deprecated: false type: path components: schemas: {} ```` --- # Source: https://docs.cursor.com/en/guides/tutorials/building-mcp-server.md # Building an MCP Server > Learn how to build a Model Context Protocol (MCP) server with PostgreSQL integration for Cursor ## Introduction MCP servers let you connect custom data sources and make them available for use inside Cursor. This is particularly useful when you need context from places such as browsers, databases, or error and system logs. Setting up an MCP server is straightforward, and with Cursor it can be done quickly. In this guide, we will walk through how to build an MCP server for Postgres. Our goal is to enable Cursor to run SQL queries directly against a Postgres database and to expose table schemas in a structured way. This tutorial is designed to teach the fundamentals of building MCP servers. ```mermaid theme={null} graph LR A[User in Cursor] --> B[Cursor] B <--> C["MCP Server (stdio)"] C <--> D[(Postgres Database)] subgraph Local Machine B C end class B cursor class C mcp class D db ``` ## What is an MCP Server? An [MCP server](/en/context/mcp) is a process that communicates with Cursor and provides access to external data or actions. It can be implemented in several ways, but here we will use the simplest method: a server that runs locally on your computer over [stdio](https://en.wikipedia.org/wiki/Standard_streams) (standard input/output streams). This avoids complicated security considerations and allows us to focus on the MCP logic itself. One of the most common use cases for MCP is database access. When building dashboards, running analyses, or creating migrations, it is often necessary to query and inspect a database. Our Postgres MCP server will support two core capabilities: running arbitrary queries and listing table schemas. Although both of these tasks could be performed with plain SQL, MCP offers features that make them more powerful and more generally useful. Tools provide a way to expose actions such as executing queries, while resources allow us to share standardized context such as schema information. Later in this guide we will also look at prompts, which enable more advanced workflows. Under the hood, we will rely on the postgres npm package to execute SQL statements against the database. The MCP SDK will serve as a wrapper around these calls, letting us integrate Postgres functionality seamlessly into Cursor. ## How to Build the MCP Server The first step in building the server is to setup a new project. We’ll start with creating a new folder and initializing a Bun project ```bash theme={null} > mkdir postgres-mcp-server > Bun init ``` From here, we’ll select `Blank` project. Once our boilerplate is setup, we need to install the required dependencies. `zod` is required to define schemas for i/o in MCP sdk ```bash theme={null} bun add postgres @modelcontextprotocol/sdk zod ``` From here, we’ll go to the repositories for each of the libraries and get the link to the raw file contents of each respective README files. We’ll use these for context when building the server * `postgres` * Repo: [https://github.com/porsager/postgres](https://github.com/porsager/postgres), * README: [https://raw.githubusercontent.com/porsager/postgres/refs/heads/master/README.md](https://raw.githubusercontent.com/porsager/postgres/refs/heads/master/README.md) * `@modelcontextprotocol/sdk`: * Repo: [https://github.com/modelcontextprotocol/typescript-sdk](https://github.com/modelcontextprotocol/typescript-sdk) * README: [https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/refs/heads/main/README.md](https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/refs/heads/main/README.md) Now, we’ll define how we want the server to behave. To do that, we’ll create a `spec.md` and write out the high level goals ```markdown theme={null} # Spec - Allow defining DATABASE_URL through MCP env configuration - Query postgres data through tool - By default, make it readonly - Allow write ops by setting ENV `DANGEROUSLY_ALLOW_WRITE_OPS=true|1` - Access tables as `resources` - Use Zod for schema definitions ``` As you can see, this is quite a lightweight spec.Fee free to ad more details as needed.. Together with the README links, we’ll construct the final prompt ```markdown theme={null} Read the following and follow @spec.md to understand what we want. All necesary dependeies are installed - @https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/refs/heads/main/README.md - @https://raw.githubusercontent.com/porsager/postgres/refs/heads/master/README.md ``` With these three components in place (the specification, the MCP SDK documentation, and the Postgres library documentation), we can use Cursor to scaffold the server implementation. Cursor will help us stitch the pieces together, generating the code that connects the MCP SDK with Postgres. After some back and forth prompting, we now have a first version of the MCP server going. To try it out, we can use the [MCP Inspector](https://modelcontextprotocol.io/legacy/tools/inspector) ```bash theme={null} npx @modelcontextprotocol/inspector bun run index.ts ``` ## Testing the MCP Server Once the initial implementation is complete, we can test it using the MCP Inspector. The inspector provides a way to see what the server exposes and to verify that the tools and resources behave as expected. We should confirm that queries can be executed and that schema information is returned correctly. MCP Inspector interface When everything looks good, we can connect the server to Cursor itself and test it in a real environment. At this point, Cursor will be able to use the Postgres MCP server as if it were a built-in capability, letting us query and inspect the database directly. ## Next Steps Running the MCP server locally over stdio is a great starting point, but teams often require shared access to the same database through their MCP server. In these scenarios, deploying the MCP server as a centralized HTTP service becomes necessary. A deployed MCP server offers several advantages over individual stdio instances: * **Shared database access:** Multiple team members can query the same database instance through Cursor * **Centralized configuration:** Schema updates and permission changes are managed in one location * **Enhanced security:** Proper authentication, rate limiting, and access controls can be implemented * **Observability:** Usage patterns and performance metrics can be monitored across the team To achieve this, you would switch the transport method from stdio to HTTP. While we won’t cover the whole setup, here’s a good starting prompt you can give to Cursor ``` Based on the existing MCP server, create a new file that implements the HTTP protocol. Move shared logic to mcp-core, and name each transport implementation by name (mcp-server-stdio, mcp-server-http) @https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/refs/heads/main/README.md ``` The final results can be seen here: [pg-mcp-server](https://github.com/ericzakariasson/pg-mcp-server) ```mermaid theme={null} graph LR subgraph Team_Network_or_Cloud["VPC"] SVC["MCP Server (HTTP transport)"] <--> DB[(Postgres DB)] end Dev1["Developer 1 on Cursor"] -->|HTTP| SVC Dev2["Developer 2 on Cursor"] -->|HTTP| SVC Dev3["Developer 3 on Cursor"] -->|HTTP| SVC subgraph SVC_Internals["Internals"] direction TB T1["Auth and ACLs"] T2["Rate limiting and logging"] T3["Tool: query"] T4["Resource: table_schemas"] T5["Prompts"] T1 --> T2 --> T3 T3 --> T4 T3 --> T5 end SVC --> SVC_Internals class SVC svc class DB db class T1,T2,T3,T4,T5 internals class Dev1,Dev2,Dev3 dev ``` --- # Source: https://docs.cursor.com/en/cli/cookbook/code-review.md # Code Review > Build a GitHub Actions workflow that uses Cursor CLI to automatically review pull requests and provide feedback This tutorial shows you how to set up code review using Cursor CLI in GitHub Actions. The workflow will analyze pull requests, identify issues, and post feedback as comments. For most users, we recommend using [Bugbot](/en/bugbot) instead. Bugbot provides managed automated code review with no setup required. This CLI approach is useful to explore capabilities and for advanced customization.
```yaml cursor-code-review.yml theme={null} name: Code Review on: pull_request: types: [opened, synchronize, reopened, ready_for_review] permissions: pull-requests: write contents: read issues: write jobs: code-review: runs-on: ubuntu-latest # Skip automated code review for draft PRs if: github.event.pull_request.draft == false steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} - name: Install Cursor CLI run: | curl https://cursor.com/install -fsS | bash echo "$HOME/.cursor/bin" >> $GITHUB_PATH - name: Configure git identity run: | git config user.name "Cursor Agent" git config user.email "cursoragent@cursor.com" - name: Perform automated code review env: CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} MODEL: gpt-5 GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BLOCKING_REVIEW: ${{ vars.BLOCKING_REVIEW || 'false' }} run: | cursor-agent --force --model "$MODEL" --output-format=text --print 'You are operating in a GitHub Actions runner performing automated code review. The gh CLI is available and authenticated via GH_TOKEN. You may comment on pull requests. Context: - Repo: ${{ github.repository }} - PR Number: ${{ github.event.pull_request.number }} - PR Head SHA: ${{ github.event.pull_request.head.sha }} - PR Base SHA: ${{ github.event.pull_request.base.sha }} - Blocking Review: ${{ env.BLOCKING_REVIEW }} Objectives: 1) Re-check existing review comments and reply resolved when addressed. 2) Review the current PR diff and flag only clear, high-severity issues. 3) Leave very short inline comments (1-2 sentences) on changed lines only and a brief summary at the end. Procedure: - Get existing comments: gh pr view --json comments - Get diff: gh pr diff - Get changed files with patches to compute inline positions: gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files --paginate --jq '.[] | {filename,patch}' - Compute exact inline anchors for each issue (file path + diff position). Comments MUST be placed inline on the changed line in the diff, not as top-level comments. - Detect prior top-level "no issues" style comments authored by this bot (match bodies like: "✅ no issues", "No issues found", "LGTM"). - If CURRENT run finds issues and any prior "no issues" comments exist: - Prefer to remove them to avoid confusion: - Try deleting top-level issue comments via: gh api -X DELETE repos/${{ github.repository }}/issues/comments/ - If deletion isn't possible, minimize them via GraphQL (minimizeComment) or edit to prefix "[Superseded by new findings]". - If neither delete nor minimize is possible, reply to that comment: "⚠️ Superseded: issues were found in newer commits". - If a previously reported issue appears fixed by nearby changes, reply: ✅ This issue appears to be resolved by the recent changes - Analyze ONLY for: - Null/undefined dereferences - Resource leaks (unclosed files or connections) - Injection (SQL/XSS) - Concurrency/race conditions - Missing error handling for critical operations - Obvious logic errors with incorrect behavior - Clear performance anti-patterns with measurable impact - Definitive security vulnerabilities - Avoid duplicates: skip if similar feedback already exists on or near the same lines. Commenting rules: - Max 10 inline comments total; prioritize the most critical issues - One issue per comment; place on the exact changed line - All issue comments MUST be inline (anchored to a file and line/position in the PR diff) - Natural tone, specific and actionable; do not mention automated or high-confidence - Use emojis: 🚨 Critical 🔒 Security ⚡ Performance ⚠️ Logic ✅ Resolved ✨ Improvement Submission: - If there are NO issues to report and an existing top-level comment indicating "no issues" already exists (e.g., "✅ no issues", "No issues found", "LGTM"), do NOT submit another comment. Skip submission to avoid redundancy. - If there are NO issues to report and NO prior "no issues" comment exists, submit one brief summary comment noting no issues. - If there ARE issues to report and a prior "no issues" comment exists, ensure that prior comment is deleted/minimized/marked as superseded before submitting the new review. - If there ARE issues to report, submit ONE review containing ONLY inline comments plus an optional concise summary body. Use the GitHub Reviews API to ensure comments are inline: - Build a JSON array of comments like: [{ "path": "", "position": , "body": "..." }] - Submit via: gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews -f event=COMMENT -f body="$SUMMARY" -f comments='[$COMMENTS_JSON]' - Do NOT use: gh pr review --approve or --request-changes Blocking behavior: - If BLOCKING_REVIEW is true and any 🚨 or 🔒 issues were posted: echo "CRITICAL_ISSUES_FOUND=true" >> $GITHUB_ENV - Otherwise: echo "CRITICAL_ISSUES_FOUND=false" >> $GITHUB_ENV - Always set CRITICAL_ISSUES_FOUND at the end ' - name: Check blocking review results if: env.BLOCKING_REVIEW == 'true' run: | echo "Checking for critical issues..." echo "CRITICAL_ISSUES_FOUND: ${CRITICAL_ISSUES_FOUND:-unset}" if [ "${CRITICAL_ISSUES_FOUND:-false}" = "true" ]; then echo "❌ Critical issues found and blocking review is enabled. Failing the workflow." exit 1 else echo "✅ No blocking issues found." fi ``` Automated code review in action showing inline comments on a pull request
## Configure authentication [Set up your API key and repository secrets](/en/cli/github-actions#authentication) to authenticate Cursor CLI in GitHub Actions. ## Set up agent permissions Create a configuration file to control what actions the agent can perform. This prevents unintended operations like pushing code or creating pull requests. Create `.cursor/cli.json` in your repository root: ```json theme={null} { "permissions": { "deny": [ "Shell(git push)", "Shell(gh pr create)", "Write(**)" ] } } ``` This configuration allows the agent to read files and use the GitHub CLI for comments, but prevents it from making changes to your repository. See the [permissions reference](/en/cli/reference/permissions) for more configuration options. ## Build the GitHub Actions workflow Now let's build the workflow step by step. ### Set up the workflow trigger Create `.github/workflows/cursor-code-review.yml` and configure it to run on pull requests: ```yaml theme={null} name: Cursor Code Review on: pull_request: types: [opened, synchronize, reopened, ready_for_review] jobs: code-review: runs-on: ubuntu-latest permissions: contents: read pull-requests: write steps: ``` ### Checkout the repository Add the checkout step to access the pull request code: ```yaml theme={null} - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} ``` ### Install Cursor CLI Add the CLI installation step: ```yaml theme={null} - name: Install Cursor CLI run: | curl https://cursor.com/install -fsS | bash echo "$HOME/.cursor/bin" >> $GITHUB_PATH ``` ### Configure the review agent Before implementing the full review step, let's understand the anatomy of our review prompt. This section outlines how we want the agent to behave: **Objective**: We want the agent to review the current PR diff and flag only clear, high-severity issues, then leave very short inline comments (1-2 sentences) on changed lines only with a brief summary at the end. This keeps the signal-to-noise ratio balanced. **Format**: We want comments that are short and to the point. We use emojis to make scanning comments easier, and we want a high-level summary of the full review at the end. **Submission**: When the review is done, we want the agent to include a short comment based on what was found during the review. The agent should submit one review containing inline comments plus a concise summary. **Edge cases**: We need to handle: * Existing comments being resolved: The agent should mark them as done when addressed * Avoid duplicates: The agent should skip commenting if similar feedback already exists on or near the same lines **Final prompt**: The complete prompt combines all these behavioral requirements to create focused, actionable feedback Now let's implement the review agent step: ```yaml theme={null} - name: Perform code review env: CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} GH_TOKEN: ${{ github.token }} run: | cursor-agent --force --model "$MODEL" --output-format=text --print "You are operating in a GitHub Actions runner performing automated code review. The gh CLI is available and authenticated via GH_TOKEN. You may comment on pull requests. Context: - Repo: ${{ github.repository }} - PR Number: ${{ github.event.pull_request.number }} - PR Head SHA: ${{ github.event.pull_request.head.sha }} - PR Base SHA: ${{ github.event.pull_request.base.sha }} Objectives: 1) Re-check existing review comments and reply resolved when addressed 2) Review the current PR diff and flag only clear, high-severity issues 3) Leave very short inline comments (1-2 sentences) on changed lines only and a brief summary at the end Procedure: - Get existing comments: gh pr view --json comments - Get diff: gh pr diff - If a previously reported issue appears fixed by nearby changes, reply: ✅ This issue appears to be resolved by the recent changes - Avoid duplicates: skip if similar feedback already exists on or near the same lines Commenting rules: - Max 10 inline comments total; prioritize the most critical issues - One issue per comment; place on the exact changed line - Natural tone, specific and actionable; do not mention automated or high-confidence - Use emojis: 🚨 Critical 🔒 Security ⚡ Performance ⚠️ Logic ✅ Resolved ✨ Improvement Submission: - Submit one review containing inline comments plus a concise summary - Use only: gh pr review --comment - Do not use: gh pr review --approve or --request-changes" ``` ```text theme={null} . ├── .cursor/ │ └── cli.json ├── .github/ │ └── workflows/ │ └── cursor-code-review.yml ``` ## Test your reviewer Create a test pull request to verify the workflow works and the agent posts review comments with emoji feedback. Pull request showing automated review comments with emojis and inline feedback on specific lines ## Next steps You now have a working automated code review system. Consider these enhancements: * Set up additional workflows for [fixing CI failures](/en/cli/cookbook/fix-ci) * Configure different review levels for different branches * Integrate with your team's existing code review process * Customize the agent's behavior for different file types or directories You can configure the workflow to fail if critical issues are found, preventing the pull request from being merged until addressed. **Add blocking behavior to the prompt** First, update your review agent step to include the `BLOCKING_REVIEW` environment variable and add this blocking behavior to the prompt: ``` Blocking behavior: - If BLOCKING_REVIEW is true and any 🚨 or 🔒 issues were posted: echo "CRITICAL_ISSUES_FOUND=true" >> $GITHUB_ENV - Otherwise: echo "CRITICAL_ISSUES_FOUND=false" >> $GITHUB_ENV - Always set CRITICAL_ISSUES_FOUND at the end ``` **Add the blocking check step** Then add this new step after your code review step: ```yaml theme={null} - name: Check blocking review results if: env.BLOCKING_REVIEW == 'true' run: | echo "Checking for critical issues..." echo "CRITICAL_ISSUES_FOUND: ${CRITICAL_ISSUES_FOUND:-unset}" if [ "${CRITICAL_ISSUES_FOUND:-false}" = "true" ]; then echo "❌ Critical issues found and blocking review is enabled. Failing the workflow." exit 1 else echo "✅ No blocking issues found." fi ``` --- # Source: https://docs.cursor.com/en/background-agent/api/delete-agent.md # Delete an Agent > Permanently delete a background agent and its associated resources. ## OpenAPI ````yaml en/background-agent/api/openapi.yaml delete /v0/agents/{id} paths: path: /v0/agents/{id} method: delete servers: - url: https://api.cursor.com description: Production server request: security: - title: bearerAuth parameters: query: {} header: Authorization: type: http scheme: bearer description: API key from Cursor Dashboard cookie: {} parameters: path: id: schema: - type: string required: true description: Unique identifier for the background agent example: bc_abc123 query: {} header: {} cookie: {} body: {} response: '200': application/json: schemaArray: - type: object properties: id: allOf: - type: string description: Unique identifier for the background agent example: bc_abc123 requiredProperties: - id examples: example: value: id: bc_abc123 description: Agent deleted successfully '400': application/json: schemaArray: - type: object properties: error: allOf: - &ref_0 type: object properties: message: type: string description: Human-readable error message code: type: string description: Machine-readable error code refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Invalid request - bad agent ID format '401': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Unauthorized - invalid or missing API key '403': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Forbidden - insufficient permissions '404': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Agent not found or access denied '409': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Conflict - agent is deleted or archived '429': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Rate limit exceeded '500': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Internal server error deprecated: false type: path components: schemas: {} ```` --- # Source: https://docs.cursor.com/en/cli/cookbook/fix-ci.md # Fix CI Failures > Fix CI issues for a repository by using Cursor CLI in GitHub Actions Fix CI failures using Cursor CLI in GitHub Actions. This workflow analyzes failures, makes targeted fixes, and creates a fix branch with a quick-create PR link. This workflow monitors a specific workflow by name. Update the `workflows` list to match your actual CI workflow name. ```yaml auto-fix-ci.yml theme={null} name: Fix CI Failures on: workflow_run: workflows: [Test] types: [completed] permissions: contents: write pull-requests: write actions: read jobs: attempt-fix: if: >- ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.name != 'Fix CI Failures' }} runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install Cursor CLI run: | curl https://cursor.com/install -fsS | bash echo "$HOME/.cursor/bin" >> $GITHUB_PATH - name: Configure git identity run: | git config user.name "Cursor Agent" git config user.email "cursoragent@cursor.com" - name: Fix CI failure env: CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} MODEL: gpt-5 GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH_PREFIX: ci-fix run: | cursor-agent -p "You are operating in a GitHub Actions runner. The GitHub CLI is available as `gh` and authenticated via `GH_TOKEN`. Git is available. You have write access to repository contents and can comment on pull requests, but you must not create or edit PRs directly. # Context: - Repo: ${{ github.repository }} - Owner: ${{ github.repository_owner }} - Workflow Run ID: ${{ github.event.workflow_run.id }} - Workflow Run URL: ${{ github.event.workflow_run.html_url }} - Fix Branch Prefix: ${{ env.BRANCH_PREFIX }} # Goal: - Implement an end-to-end CI fix flow driven by the failing PR, creating a separate persistent fix branch and proposing a quick-create PR back into the original PR's branch. # Requirements: 1) Identify the PR associated with the failed workflow run and determine its base and head branches. Let HEAD_REF be the PR's head branch (the contributor/origin branch). 2) Maintain a persistent fix branch for this PR head using the Fix Branch Prefix from Context. Create it if missing, update it otherwise, and push changes to origin. 3) Attempt to resolve the CI failure by making minimal, targeted edits consistent with the repo's style. Keep changes scoped and safe. 4) You do NOT have permission to create PRs. Instead, post or update a single natural-language PR comment (1–2 sentences) that briefly explains the CI fix and includes an inline compare link to quick-create a PR. # Inputs and conventions: - Use `gh api`, `gh run view`, `gh pr view`, `gh pr diff`, `gh pr list`, `gh run download`, and git commands as needed to discover the failing PR and branches. - Avoid duplicate comments; if a previous bot comment exists, update it instead of posting a new one. - If no actionable fix is possible, make no changes and post no comment. # Deliverables when updates occur: - Pushed commits to the persistent fix branch for this PR head. - A single natural-language PR comment on the original PR that includes the inline compare link above. " --force --model "$MODEL" --output-format=text ``` --- # Source: https://docs.cursor.com/en/background-agent/api/launch-an-agent.md # Launch an Agent > Start a new background agent to work on your repository. ## OpenAPI ````yaml en/background-agent/api/openapi.yaml post /v0/agents paths: path: /v0/agents method: post servers: - url: https://api.cursor.com description: Production server request: security: - title: bearerAuth parameters: query: {} header: Authorization: type: http scheme: bearer description: API key from Cursor Dashboard cookie: {} parameters: path: {} query: {} header: {} cookie: {} body: application/json: schemaArray: - type: object properties: prompt: allOf: - type: object required: - text properties: text: type: string minLength: 1 description: The task or instructions for the agent to execute example: Add a README.md file with installation instructions images: type: array maxItems: 5 items: $ref: '#/components/schemas/Image' description: Optional array of base64 encoded images (max 5) example: - data: iVBORw0KGgoAAAANSUhEUgAA... dimension: width: 1024 height: 768 model: allOf: - type: string minLength: 1 description: The LLM to use example: claude-4-sonnet source: allOf: - type: object required: - repository properties: repository: type: string minLength: 1 description: The GitHub repository URL example: https://github.com/your-org/your-repo ref: type: string minLength: 1 description: Git ref (branch/tag) to use as the base branch example: main target: allOf: - type: object properties: autoCreatePr: type: boolean description: >- Whether to automatically create a pull request when the agent completes default: false branchName: type: string minLength: 1 description: Custom branch name for the agent to create example: feature/add-readme webhook: allOf: - type: object required: - url properties: url: type: string format: uri maxLength: 2048 description: >- URL to receive webhook notifications about agent status changes example: https://example.com/webhooks/cursor-agent secret: type: string minLength: 32 maxLength: 256 description: Secret key for webhook payload verification example: your-webhook-secret-key-minimum-32-characters required: true refIdentifier: '#/components/schemas/CreateAgentRequest' requiredProperties: - prompt - source examples: example: value: prompt: text: Add a README.md file with installation instructions images: - data: iVBORw0KGgoAAAANSUhEUgAA... dimension: width: 1024 height: 768 model: claude-4-sonnet source: repository: https://github.com/your-org/your-repo ref: main target: autoCreatePr: false branchName: feature/add-readme webhook: url: https://example.com/webhooks/cursor-agent secret: your-webhook-secret-key-minimum-32-characters response: '201': application/json: schemaArray: - type: object properties: id: allOf: - type: string description: Unique identifier for the background agent example: bc_abc123 name: allOf: - type: string description: Name for the agent example: Add README Documentation status: allOf: - type: string enum: - CREATING description: Initial status of the newly created agent example: CREATING source: allOf: - type: object required: - repository properties: repository: type: string description: The GitHub repository URL example: https://github.com/your-org/your-repo ref: type: string description: Git ref (branch/tag) used as the base branch example: main target: allOf: - type: object required: - url properties: branchName: type: string description: The Git branch name where the agent is working example: cursor/add-readme-1234 url: type: string description: URL to view the agent in Cursor Web example: https://cursor.com/agents?id=bc_abc123 autoCreatePr: type: boolean description: Whether a pull request will be automatically created example: false createdAt: allOf: - type: string format: date-time description: When the agent was created example: '2024-01-15T10:30:00Z' requiredProperties: - id - name - status - source - target - createdAt examples: example: value: id: bc_abc123 name: Add README Documentation status: CREATING source: repository: https://github.com/your-org/your-repo ref: main target: branchName: cursor/add-readme-1234 url: https://cursor.com/agents?id=bc_abc123 autoCreatePr: false createdAt: '2024-01-15T10:30:00Z' description: Agent created successfully '400': application/json: schemaArray: - type: object properties: error: allOf: - &ref_0 type: object properties: message: type: string description: Human-readable error message code: type: string description: Machine-readable error code refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Invalid request '401': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Unauthorized - invalid or missing API key '403': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: >- Forbidden - insufficient permissions, plan limits exceeded, or storage full '429': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Rate limit exceeded '500': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Internal server error deprecated: false type: path components: schemas: ImageDimension: type: object required: - width - height properties: width: type: integer minimum: 1 description: Width must be a positive integer height: type: integer minimum: 1 description: Height must be a positive integer Image: type: object required: - data properties: data: type: string minLength: 1 description: Base64 encoded image data example: iVBORw0KGgoAAAANSUhEUgAA... dimension: $ref: '#/components/schemas/ImageDimension' ```` --- # Source: https://docs.cursor.com/en/background-agent/api/list-agents.md # List Agents > Retrieve a paginated list of all background agents for the authenticated user. ## OpenAPI ````yaml en/background-agent/api/openapi.yaml get /v0/agents paths: path: /v0/agents method: get servers: - url: https://api.cursor.com description: Production server request: security: - title: bearerAuth parameters: query: {} header: Authorization: type: http scheme: bearer description: API key from Cursor Dashboard cookie: {} parameters: path: {} query: limit: schema: - type: integer required: false description: Number of background agents to return maximum: 100 minimum: 1 default: 20 cursor: schema: - type: string required: false description: Pagination cursor from the previous response minLength: 1 example: bc_xyz789 header: {} cookie: {} body: {} response: '200': application/json: schemaArray: - type: object properties: agents: allOf: - type: array description: List of agents items: type: object required: - id - name - status - source - target - createdAt properties: id: type: string description: Unique identifier for the background agent example: bc_abc123 name: type: string description: Name for the agent example: Add README Documentation status: type: string enum: - RUNNING - FINISHED - ERROR - CREATING - EXPIRED description: Current status of the background agent example: RUNNING source: type: object properties: repository: type: string description: The GitHub repository URL example: https://github.com/your-org/your-repo ref: type: string description: Git ref (branch/tag) used as the base branch example: main target: type: object required: - url properties: branchName: type: string description: The Git branch name where the agent is working example: cursor/add-readme-1234 url: type: string description: URL to view the agent in Cursor Web example: https://cursor.com/agents?id=bc_abc123 prUrl: type: string description: URL to view the pull request in GitHub, if any example: https://github.com/your-org/your-repo/pull/1234 autoCreatePr: type: boolean description: >- Whether a pull request will be automatically created example: false summary: type: string description: Summary of the agent's work example: >- Added README.md with installation instructions and usage examples createdAt: type: string format: date-time description: When the agent was created example: '2024-01-15T10:30:00Z' nextCursor: allOf: - type: string description: Cursor for fetching the next page of results example: bc_def456 requiredProperties: - agents examples: example: value: agents: - id: bc_abc123 name: Add README Documentation status: RUNNING source: repository: https://github.com/your-org/your-repo ref: main target: branchName: cursor/add-readme-1234 url: https://cursor.com/agents?id=bc_abc123 prUrl: https://github.com/your-org/your-repo/pull/1234 autoCreatePr: false summary: >- Added README.md with installation instructions and usage examples createdAt: '2024-01-15T10:30:00Z' nextCursor: bc_def456 description: Agents retrieved successfully '400': application/json: schemaArray: - type: object properties: error: allOf: - &ref_0 type: object properties: message: type: string description: Human-readable error message code: type: string description: Machine-readable error code refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Invalid request - bad query parameters '401': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Unauthorized - invalid or missing API key '403': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Forbidden - insufficient permissions '429': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Rate limit exceeded '500': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Internal server error deprecated: false type: path components: schemas: {} ```` --- # Source: https://docs.cursor.com/en/background-agent/api/list-models.md # List Models > Retrieve a list of recommended models for background agents. ## OpenAPI ````yaml en/background-agent/api/openapi.yaml get /v0/models paths: path: /v0/models method: get servers: - url: https://api.cursor.com description: Production server request: security: - title: bearerAuth parameters: query: {} header: Authorization: type: http scheme: bearer description: API key from Cursor Dashboard cookie: {} parameters: path: {} query: {} header: {} cookie: {} body: {} response: '200': application/json: schemaArray: - type: object properties: models: allOf: - type: array description: Array of available model names items: type: string minLength: 1 example: - claude-4-sonnet-thinking - o3 - claude-4-opus-thinking requiredProperties: - models examples: example: value: models: - claude-4-sonnet-thinking - o3 - claude-4-opus-thinking description: Models retrieved successfully '401': application/json: schemaArray: - type: object properties: error: allOf: - &ref_0 type: object properties: message: type: string description: Human-readable error message code: type: string description: Machine-readable error code refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Unauthorized - invalid or missing API key '429': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Rate limit exceeded '500': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Internal server error deprecated: false type: path components: schemas: {} ```` --- # Source: https://docs.cursor.com/en/background-agent/api/list-repositories.md # List GitHub Repositories > Retrieve a list of GitHub repositories accessible to the authenticated user. ## OpenAPI ````yaml en/background-agent/api/openapi.yaml get /v0/repositories paths: path: /v0/repositories method: get servers: - url: https://api.cursor.com description: Production server request: security: - title: bearerAuth parameters: query: {} header: Authorization: type: http scheme: bearer description: API key from Cursor Dashboard cookie: {} parameters: path: {} query: {} header: {} cookie: {} body: {} response: '200': application/json: schemaArray: - type: object properties: repositories: allOf: - type: array description: Array of GitHub repositories the user has access to items: type: object required: - owner - name - repository properties: owner: type: string description: The owner of the repository (user or organization) example: your-org name: type: string description: The name of the repository example: your-repo repository: type: string format: uri description: The full URL to the GitHub repository example: https://github.com/your-org/your-repo requiredProperties: - repositories examples: example: value: repositories: - owner: your-org name: your-repo repository: https://github.com/your-org/your-repo description: Repositories retrieved successfully '401': application/json: schemaArray: - type: object properties: error: allOf: - &ref_0 type: object properties: message: type: string description: Human-readable error message code: type: string description: Machine-readable error code refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Unauthorized - invalid or missing API key '429': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Rate limit exceeded '500': application/json: schemaArray: - type: object properties: error: allOf: - *ref_0 refIdentifier: '#/components/schemas/Error' examples: example: value: error: message: code: description: Internal server error deprecated: false type: path components: schemas: {} ```` --- # Source: https://docs.cursor.com/en/cli/cookbook/secret-audit.md # Secret Audit > Audit secrets for a repository by using Cursor CLI in GitHub Actions Audit your repository for security vulnerabilities and secrets exposure using Cursor CLI. This workflow scans for potential secrets, detects risky workflow patterns, and proposes security fixes. ```yaml auto-secret-audit.yml theme={null} name: Secrets Audit on: schedule: - cron: "0 4 * * *" workflow_dispatch: permissions: contents: write pull-requests: write actions: read jobs: secrets-audit: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install Cursor CLI run: | curl https://cursor.com/install -fsS | bash echo "$HOME/.cursor/bin" >> $GITHUB_PATH - name: Configure git identity run: | git config user.name "Cursor Agent" git config user.email "cursoragent@cursor.com" - name: Scan and propose hardening env: CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} MODEL: gpt-5 GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH_PREFIX: audit run: | cursor-agent -p "You are operating in a GitHub Actions runner. The GitHub CLI is available as `gh` and authenticated via `GH_TOKEN`. Git is available. You have write access to repository contents and can comment on pull requests, but you must not create or edit PRs directly. # Context: - Repo: ${{ github.repository }} - Hardening Branch Prefix: ${{ env.BRANCH_PREFIX }} # Goal: - Perform a repository secrets exposure and workflow hardening audit on a schedule, and propose minimal safe fixes. # Requirements: 1) Scan for potential secrets in tracked files and recent history; support allowlist patterns if present (e.g., .gitleaks.toml). 2) Detect risky workflow patterns: unpinned actions, overbroad permissions, unsafe pull_request_target usage, secrets in forked PR contexts, deprecated insecure commands, missing permissions blocks. 3) Maintain a persistent branch for this run using the Hardening Branch Prefix from Context. Create it if missing, update it otherwise, and push changes to origin. 4) Propose minimal edits: redact literals where safe, add ignore rules, pin actions to SHA, reduce permissions, add guardrails to workflows, and add a SECURITY_LOG.md summarizing changes and remediation guidance. 5) Push to origin. 6) If there is at least one open PR in the repo, post or update a single natural-language comment (1–2 sentences) on the most recently updated open PR that briefly explains the hardening changes and includes an inline compare link to quick-create a PR. 7) Avoid duplicate comments; update an existing bot comment if present. If no changes or no open PRs, post nothing. # Inputs and conventions: - Use `gh` to list PRs and to post comments. Avoid duplicate comments. # Deliverables when updates occur: - Pushed commits to the persistent hardening branch for this run. - A single natural-language PR comment with the compare link above (only if an open PR exists). " --force --model "$MODEL" --output-format=text ``` --- # Source: https://docs.cursor.com/en/cli/cookbook/translate-keys.md # Translate Keys > Translate keys for a repository by using Cursor CLI in GitHub Actions Manage translation keys for internationalization using Cursor CLI. This workflow detects new or changed i18n keys in pull requests and fills missing translations without overwriting existing ones. ```yaml auto-translate-keys.yml theme={null} name: Translate Keys on: pull_request: types: [opened, synchronize, reopened, ready_for_review] permissions: contents: write pull-requests: write jobs: i18n: if: ${{ !startsWith(github.head_ref, 'translate/') }} runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install Cursor CLI run: | curl https://cursor.com/install -fsS | bash echo "$HOME/.cursor/bin" >> $GITHUB_PATH - name: Configure git identity run: | git config user.name "Cursor Agent" git config user.email "cursoragent@cursor.com" - name: Propose i18n updates env: CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} MODEL: gpt-5 GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH_PREFIX: translate run: | cursor-agent -p "You are operating in a GitHub Actions runner. The GitHub CLI is available as `gh` and authenticated via `GH_TOKEN`. Git is available. You have write access to repository contents and can comment on pull requests, but you must not create or edit PRs directly. # Context: - Repo: ${{ github.repository }} - PR Number: ${{ github.event.pull_request.number }} - Head Ref: ${{ github.head_ref }} - Translate Branch Prefix: ${{ env.BRANCH_PREFIX }} # Goal: - Detect i18n keys added or changed in the PR and fill only missing locales in message files. Never overwrite existing translations. # Requirements: 1) Determine changed keys by inspecting the PR diff (source files and messages files). 2) Compute missing keys per locale using the source/canonical locale as truth. 3) Add entries only for missing keys. Preserve all existing values untouched. 4) Validate JSON formatting and schemas. 5) Maintain a persistent translate branch for this PR head using the Translate Branch Prefix from Context. Create it if missing, update it otherwise, and push changes to origin. 6) Post or update a single PR comment on the original PR written in natural language (1–2 sentences) that briefly explains what was updated and why, and includes an inline compare link to quick-create a PR. 7) Avoid duplicate comments; update a previous bot comment if present. 8) If no changes are necessary, make no commits and post no comment. # Inputs and conventions: - Use `gh pr diff` and git history to detect changes. # Deliverables when updates occur: - Pushed commits to the persistent translate branch for this PR head. - A single natural-language PR comment on the original PR with the compare link above. " --force --model "$MODEL" --output-format=text ``` --- # Source: https://docs.cursor.com/en/cli/cookbook/update-docs.md # Update Docs > Update docs for a repository by using Cursor CLI in GitHub Actions Update documentation using Cursor CLI in GitHub Actions. Two approaches: full agent autonomy or deterministic workflow with agent-only file modifications. ```yaml auto-update-docs.yml theme={null} name: Update Docs on: pull_request: types: [opened, synchronize, reopened, ready_for_review] permissions: contents: write pull-requests: write jobs: auto-docs: if: ${{ !startsWith(github.head_ref, 'docs/') }} runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install Cursor CLI run: | curl https://cursor.com/install -fsS | bash echo "$HOME/.cursor/bin" >> $GITHUB_PATH - name: Configure git run: | git config user.name "Cursor Agent" git config user.email "cursoragent@cursor.com" - name: Update docs env: MODEL: gpt-5 CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH_PREFIX: docs run: | cursor-agent -p "You are operating in a GitHub Actions runner. The GitHub CLI is available as `gh` and authenticated via `GH_TOKEN`. Git is available. You have write access to repository contents and can comment on pull requests, but you must not create or edit PRs. # Context: - Repo: ${{ github.repository }} - Owner: ${{ github.repository_owner }} - PR Number: ${{ github.event.pull_request.number }} - Base Ref: ${{ github.base_ref }} - Head Ref: ${{ github.head_ref }} - Docs Branch Prefix: ${{ env.BRANCH_PREFIX }} # Goal: - Implement an end-to-end docs update flow driven by incremental changes to the original PR. # Requirements: 1) Determine what changed in the original PR and, if there have been multiple pushes, compute the incremental diffs since the last successful docs update. 2) Update only the relevant docs based on those incremental changes. 3) Maintain the persistent docs branch for this PR head using the Docs Branch Prefix from Context. Create it if missing, update it otherwise, and push changes to origin. 4) You do NOT have permission to create PRs. Instead, post or update a single natural-language PR comment (1–2 sentences) that briefly explains the docs updates and includes an inline compare link to quick-create a PR # Inputs and conventions: - Use `gh pr diff` and git history to detect changes and derive incremental ranges since the last docs update. - Do not attempt to create or edit PRs directly. Use the compare link format above. - Keep changes minimal and consistent with repo style. If no doc updates are necessary, make no changes and post no comment. # Deliverables when updates occur: - Pushed commits to the persistent docs branch for this PR head. - A single natural-language PR comment on the original PR that includes the inline compare link above. Avoid posting duplicates; update a previous bot comment if present. " --force --model "$MODEL" --output-format=text ``` ```yaml auto-update-docs-deterministic.yml theme={null} name: Update Docs on: pull_request: types: [opened, synchronize, reopened, ready_for_review] permissions: contents: write pull-requests: write jobs: auto-docs: if: ${{ !startsWith(github.head_ref, 'docs/') }} runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install Cursor CLI run: | curl https://cursor.com/install -fsS | bash echo "$HOME/.cursor/bin" >> $GITHUB_PATH - name: Configure git run: | git config user.name "Cursor Agent" git config user.email "cursoragent@cursor.com" - name: Generate docs updates (no commit/push/comment) env: MODEL: gpt-5 CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH_PREFIX: docs run: | cursor-agent -p "You are operating in a GitHub Actions runner. The GitHub CLI is available as `gh` and authenticated via `GH_TOKEN`. Git is available. IMPORTANT: Do NOT create branches, commit, push, or post PR comments. Only modify files in the working directory as needed. A later workflow step is responsible for publishing changes and commenting on the PR. # Context: - Repo: ${{ github.repository }} - Owner: ${{ github.repository_owner }} - PR Number: ${{ github.event.pull_request.number }} - Base Ref: ${{ github.base_ref }} - Head Ref: ${{ github.head_ref }} # Goal: - Update repository documentation based on incremental changes introduced by this PR. # Requirements: 1) Determine what changed in the original PR (use `gh pr diff` and git history as needed). If an existing persistent docs branch `${{ env.BRANCH_PREFIX }}/${{ github.head_ref }}` exists, you may use it as a read-only reference point to understand prior updates. 2) Update only the relevant docs based on those changes. Keep edits minimal and consistent with repo style. 3) Do NOT commit, push, create branches, or post PR comments. Leave the working tree with updated files only; a later step will publish. # Inputs and conventions: - Use `gh pr diff` and git history to detect changes and focus documentation edits accordingly. - If no doc updates are necessary, make no changes and produce no output. # Deliverables when updates occur: - Modified documentation files in the working directory only (no commits/pushes/comments). " --force --model "$MODEL" --output-format=text - name: Publish docs branch id: publish_docs env: BRANCH_PREFIX: docs HEAD_REF: ${{ github.head_ref }} PR_NUMBER: ${{ github.event.pull_request.number }} run: | echo "changes_published=false" >> "$GITHUB_OUTPUT" DOCS_BRANCH="${BRANCH_PREFIX}/${HEAD_REF}" # Ensure we are on a local branch that we can push git fetch origin --prune # Create/switch to the persistent docs branch, keeping current working tree changes git checkout -B "$DOCS_BRANCH" # Stage and detect changes git add -A if git diff --staged --quiet; then echo "No docs changes to publish. Skipping commit/push." exit 0 fi COMMIT_MSG="docs: update for PR #${PR_NUMBER} (${HEAD_REF} @ $(git rev-parse --short HEAD))" git commit -m "$COMMIT_MSG" git push --set-upstream origin "$DOCS_BRANCH" echo "changes_published=true" >> "$GITHUB_OUTPUT" - name: Post or update PR comment if: steps.publish_docs.outputs.changes_published == 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH_PREFIX: docs REPO: ${{ github.repository }} BASE_REF: ${{ github.base_ref }} HEAD_REF: ${{ github.head_ref }} PR_NUMBER: ${{ github.event.pull_request.number }} run: | DOCS_BRANCH="${BRANCH_PREFIX}/${HEAD_REF}" COMPARE_URL="https://github.com/${REPO}/compare/${BASE_REF}...${DOCS_BRANCH}?quick_pull=1&title=docs%3A+updates+for+PR+%23${PR_NUMBER}" COMMENT_FILE="${RUNNER_TEMP}/auto-docs-comment.md" { echo "Cursor updated docs branch: \`${DOCS_BRANCH}\`" echo "You can now [view the diff and quick-create a PR to merge these docs updates](${COMPARE_URL})." echo echo "_This comment will be updated on subsequent runs as the PR changes._" echo echo "" } > "$COMMENT_FILE" # If editing the last bot comment fails (older gh), fall back to creating a new comment if gh pr comment "$PR_NUMBER" --body-file "$COMMENT_FILE" --edit-last; then echo "Updated existing PR comment." else gh pr comment "$PR_NUMBER" --body-file "$COMMENT_FILE" echo "Posted new PR comment." fi ``` --- # Source: https://docs.cursor.com/en/background-agent/api/webhooks.md # Webhooks > Receive real-time notifications about background agent status changes # Webhooks When you create an agent with a webhook URL, Cursor will send HTTP POST requests to notify you about status changes. Currently, only `statusChange` events are supported, specifically when an agent encounters an `ERROR` or `FINISHED` state. ## Webhook verification To ensure the webhook requests are authentically from Cursor, verify the signature included with each request: ### Headers Each webhook request includes the following headers: * **`X-Webhook-Signature`** – Contains the HMAC-SHA256 signature in the format `sha256=` * **`X-Webhook-ID`** – A unique identifier for this delivery (useful for logging) * **`X-Webhook-Event`** – The event type (currently only `statusChange`) * **`User-Agent`** – Always set to `Cursor-Agent-Webhook/1.0` ### Signature verification To verify the webhook signature, compute the expected signature and compare it with the received signature: ```javascript theme={null} const crypto = require('crypto'); function verifyWebhook(secret, rawBody, signature) { const expectedSignature = 'sha256=' + crypto.createHmac('sha256', secret) .update(rawBody) .digest('hex'); return signature === expectedSignature; } ``` ```python theme={null} import hmac import hashlib def verify_webhook(secret, raw_body, signature): expected_signature = 'sha256=' + hmac.new( secret.encode(), raw_body, hashlib.sha256 ).hexdigest() return signature == expected_signature ``` Always use the raw request body (before any parsing) when computing the signature. ## Payload format The webhook payload is sent as JSON with the following structure: ```json theme={null} { "event": "statusChange", "timestamp": "2024-01-15T10:30:00Z", "id": "bc_abc123", "status": "FINISHED", "source": { "repository": "https://github.com/your-org/your-repo", "ref": "main" }, "target": { "url": "https://cursor.com/agents?id=bc_abc123", "branchName": "cursor/add-readme-1234", "prUrl": "https://github.com/your-org/your-repo/pull/1234" }, "summary": "Added README.md with installation instructions" } ``` Note that some fields are optional and will only be included when available. ## Best practices * **Verify signatures** – Always verify the webhook signature to ensure the request is from Cursor * **Handle retries** – Webhooks may be retried if your endpoint returns an error status code * **Return quickly** – Return a 2xx status code as soon as possible * **Use HTTPS** – Always use HTTPS URLs for webhook endpoints in production * **Store raw payloads** – Store the raw webhook payload for debugging and future verification