Skip to content
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions registry/coder/modules/cursor-cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
display_name: Cursor CLI
description: Run Cursor CLI agent in your workspace
icon: ../../../../.icons/cursor.svg
verified: true
tags: [cli, cursor, ai, agent]
---

# Cursor CLI

Run the [Cursor CLI](https://docs.cursor.com/en/cli/overview) agent in your workspace for terminal-based AI coding assistance.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a screenshot with this and Coder Tasks?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea! I'll add a screenshot showing the cursor-cli module working with Coder Tasks. Let me set that up and add it to the README.


```tf
module "cursor-cli" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/cursor-cli/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
folder = "/home/coder"
}
```

## Prerequisites

- You must add the [Coder Login](https://registry.coder.com/modules/coder-login) module to your template

## Features

- **CLI Agent**: Terminal-based AI coding assistant with interactive and non-interactive modes
- **AgentAPI Integration**: Web interface for CLI interactions
- **Interactive Mode**: Conversational sessions with text output
- **Non-Interactive Mode**: Automation-friendly for scripts and CI pipelines
- **Session Management**: List, resume, and manage coding sessions
- **Model Selection**: Support for multiple AI models (GPT-5, Claude, etc.)
- **MCP Support**: Model Context Protocol for extended functionality
- **Rules System**: Custom agent behavior configuration

## Examples
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have an example of how to use with Coder Tasks?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely! I'll add a comprehensive example showing how to integrate cursor-cli with Coder Tasks for automated workflows. This will include both interactive and non-interactive usage patterns.


### Basic setup

```tf
module "coder-login" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/coder-login/coder"
version = "1.0.15"
agent_id = coder_agent.example.id
}

module "cursor-cli" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/cursor-cli/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
install_cursor_cli = true
install_agentapi = true
}
```

### CLI only (no web interface)

```tf
module "cursor-cli" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/cursor-cli/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
install_cursor_cli = true
install_agentapi = false
}
```

### With custom pre-install script

```tf
module "cursor-cli" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/cursor-cli/coder"
version = "1.0.0"
agent_id = coder_agent.example.id

pre_install_script = <<-EOT
# Install additional dependencies
npm install -g typescript
EOT
}
```

## Usage

### Web Interface

1. Click the "Cursor CLI" button to access the web interface
2. Start interactive sessions with text output

### Terminal Usage

```bash
# Interactive mode (default)
cursor-agent

# Interactive mode with initial prompt
cursor-agent "refactor the auth module to use JWT tokens"

# Non-interactive mode with text output
cursor-agent -p "find and fix performance issues" --output-format text

# Use specific model
cursor-agent -p "add error handling" --model "gpt-5"

# Session management
cursor-agent ls # List all previous chats
cursor-agent resume # Resume latest conversation
cursor-agent --resume="chat-id" # Resume specific conversation
```

### Interactive Mode Features

- Conversational sessions with the agent
- Review proposed changes before applying
- Real-time guidance and steering
- Text-based output optimized for terminal use
- Session persistence and resumption

### Non-Interactive Mode Features

- Automation-friendly for scripts and CI pipelines
- Direct prompt execution with text output
- Model selection support
- Git integration for change reviews

## Configuration

The module supports the same configuration options as the Cursor CLI:

- **MCP (Model Context Protocol)**: Automatically detects `mcp.json` configuration
- **Rules System**: Supports `.cursor/rules` directory for custom agent behavior
- **Environment Variables**: Respects Cursor CLI environment settings

## Troubleshooting

The module creates log files in the workspace's `~/.cursor-cli-module` directory. Check these files if you encounter issues:

```bash
# Check installation logs
cat ~/.cursor-cli-module/install.log

# Check runtime logs
cat ~/.cursor-cli-module/runtime.log

# Verify Cursor CLI installation
cursor-agent --help
```

### Common Issues

1. **Cursor CLI not found**: Ensure `install_cursor_cli = true` or install manually:

```bash
curl https://cursor.com/install -fsS | bash
```

2. **Permission issues**: Check that the installation script has proper permissions

3. **Path issues**: The module automatically adds Cursor CLI to PATH, but you may need to restart your shell
80 changes: 80 additions & 0 deletions registry/coder/modules/cursor-cli/main.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { describe, expect, it } from "bun:test";
import {
runTerraformApply,
runTerraformInit,
testRequiredVariables,
} from "~test";

describe("cursor-cli", async () => {
await runTerraformInit(import.meta.dir);

testRequiredVariables(import.meta.dir, {
agent_id: "foo",
});

it("default output with CLI enabled", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
});

// Check that AgentAPI module is created
const agentapi_module = state.resources.find(
(res) => res.type === "module" && res.name === "agentapi",
);
expect(agentapi_module).not.toBeNull();
});

it("adds custom folder", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
folder: "/foo/bar",
});

// Check that AgentAPI module is created with custom folder
const agentapi_module = state.resources.find(
(res) => res.type === "module" && res.name === "agentapi",
);
expect(agentapi_module).not.toBeNull();
});

it("expect order to be set", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
order: "22",
});

// Check that AgentAPI module is created
const agentapi_module = state.resources.find(
(res) => res.type === "module" && res.name === "agentapi",
);
expect(agentapi_module).not.toBeNull();
});

it("disables CLI installation", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
install_cursor_cli: "false",
install_agentapi: "false",
});

// AgentAPI module should still exist but with install_agentapi = false
const agentapi_module = state.resources.find(
(res) => res.type === "module" && res.name === "agentapi",
);
expect(agentapi_module).not.toBeNull();
});

it("enables only CLI without web interface", async () => {
const state = await runTerraformApply(import.meta.dir, {
agent_id: "foo",
install_cursor_cli: "true",
install_agentapi: "false",
});

// AgentAPI module should exist but with install_agentapi = false
const agentapi_module = state.resources.find(
(res) => res.type === "module" && res.name === "agentapi",
);
expect(agentapi_module).not.toBeNull();
});
});
119 changes: 119 additions & 0 deletions registry/coder/modules/cursor-cli/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
terraform {
required_version = ">= 1.0"

required_providers {
coder = {
source = "coder/coder"
version = ">= 2.7"
}
}
}

variable "agent_id" {
type = string
description = "The ID of a Coder agent."
}

data "coder_workspace" "me" {}

data "coder_workspace_owner" "me" {}

variable "order" {
type = number
description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)."
default = null
}

variable "group" {
type = string
description = "The name of a group that this app belongs to."
default = null
}

variable "icon" {
type = string
description = "The icon to use for the app."
default = "/icon/cursor.svg"
}

variable "folder" {
type = string
description = "The folder to run Cursor CLI in."
default = "/home/coder"
}

variable "install_cursor_cli" {
type = bool
description = "Whether to install Cursor CLI."
default = true
}

variable "install_agentapi" {
type = bool
description = "Whether to install AgentAPI."
default = true
}

variable "agentapi_version" {
type = string
description = "The version of AgentAPI to install."
default = "v0.3.3"
}

variable "subdomain" {
type = bool
description = "Whether to use a subdomain for AgentAPI."
default = true
}

variable "pre_install_script" {
type = string
description = "Custom script to run before installing Cursor CLI."
default = null
}

variable "post_install_script" {
type = string
description = "Custom script to run after installing Cursor CLI."
default = null
}

locals {
app_slug = "cursor-cli"
install_script = file("${path.module}/scripts/install.sh")
start_script = file("${path.module}/scripts/start.sh")
module_dir_name = ".cursor-cli-module"
}

module "agentapi" {
source = "registry.coder.com/coder/agentapi/coder"
version = "1.1.0"

agent_id = var.agent_id
web_app_slug = local.app_slug
web_app_order = var.order
web_app_group = var.group
web_app_icon = var.icon
web_app_display_name = "Cursor CLI"
cli_app_slug = "${local.app_slug}-terminal"
cli_app_display_name = "Cursor CLI Terminal"
module_dir_name = local.module_dir_name
install_agentapi = var.install_agentapi
agentapi_version = var.agentapi_version
agentapi_subdomain = var.subdomain
pre_install_script = var.pre_install_script
post_install_script = var.post_install_script
start_script = local.start_script
install_script = <<-EOT
#!/bin/bash
set -o errexit
set -o pipefail

echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh
chmod +x /tmp/install.sh

ARG_FOLDER='${var.folder}' \
ARG_INSTALL='${var.install_cursor_cli}' \
/tmp/install.sh
EOT
}
Loading