Skip to content

Commit 395b650

Browse files
covlllpclaude
andcommitted
feat: add Cursor CLI (agent) support
Add Cursor as a supported agent using the new centralized registry. Cursor CLI is built on Claude Code's codebase, so status detection delegates to the existing Claude detector. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1b5ecb8 commit 395b650

10 files changed

Lines changed: 76 additions & 12 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Run multiple AI agents in parallel across different branches of your codebase, e
2424

2525
## Features
2626

27-
- **Multi-agent support** -- Claude Code, OpenCode, Mistral Vibe, Codex CLI, and Gemini CLI
27+
- **Multi-agent support** -- Claude Code, OpenCode, Mistral Vibe, Codex CLI, Gemini CLI, and Cursor CLI
2828
- **TUI dashboard** -- visual interface to create, monitor, and manage sessions
2929
- **Agent + terminal views** -- toggle between your AI agents and paired shell terminals with `t`
3030
- **Status detection** -- see which agents are running, waiting for input, or idle
@@ -95,7 +95,7 @@ Nothing. Sessions are tmux sessions running in the background. Open and close `a
9595

9696
### Which AI tools are supported?
9797

98-
Claude Code, OpenCode, Mistral Vibe, Codex CLI, and Gemini CLI. AoE auto-detects which are installed on your system.
98+
Claude Code, OpenCode, Mistral Vibe, Codex CLI, Gemini CLI, and Cursor CLI. AoE auto-detects which are installed on your system.
9999

100100
## Troubleshooting
101101

docs/cli/reference.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ This document contains the help content for the `aoe` command-line program.
4343

4444
## `aoe`
4545

46-
Agent of Empires (aoe) is a terminal session manager that uses tmux to help you manage and monitor AI coding agents like Claude Code and OpenCode.
46+
Agent of Empires (aoe) is a terminal session manager that uses tmux to help you manage and monitor AI coding agents like Claude Code, OpenCode, and Cursor CLI.
4747

4848
Run without arguments to launch the TUI dashboard.
4949

@@ -87,7 +87,7 @@ Add a new session
8787

8888
* `-t`, `--title <TITLE>` — Session title (defaults to folder name)
8989
* `-g`, `--group <GROUP>` — Group path (defaults to parent folder)
90-
* `-c`, `--cmd <COMMAND>` — Command to run (e.g., 'claude', 'opencode', 'vibe', 'codex', 'gemini')
90+
* `-c`, `--cmd <COMMAND>` — Command to run (e.g., 'claude', 'opencode', 'vibe', 'codex', 'gemini', 'cursor')
9191
* `-P`, `--parent <PARENT>` — Parent session (creates sub-session, inherits group)
9292
* `-l`, `--launch` — Launch the session immediately after creating
9393
* `-w`, `--worktree <WORKTREE_BRANCH>` — Create session in a git worktree for the specified branch

docs/guides/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ All settings below can also be edited from the TUI settings screen (press `s` or
4141

4242
```toml
4343
[session]
44-
default_tool = "claude" # claude, opencode, vibe, codex, gemini
44+
default_tool = "claude" # claude, opencode, vibe, codex, gemini, cursor
4545
```
4646

4747
| Option | Default | Description |

docs/guides/repo-config.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ For sandboxed sessions, hooks run inside the Docker container.
4040
default_tool = "opencode" # Override the default agent for this repo
4141
```
4242

43-
Available tools: `claude`, `opencode`, `vibe`, `codex`, `gemini`.
43+
Available tools: `claude`, `opencode`, `vibe`, `codex`, `gemini`, `cursor`.
4444

4545
### Sandbox
4646

docs/guides/sandbox.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Overview
44

5-
Docker sandboxing runs your AI coding agents (Claude Code, OpenCode, Mistral Vibe, Codex CLI, Gemini CLI) inside isolated Docker containers while maintaining access to your project files and credentials.
5+
Docker sandboxing runs your AI coding agents (Claude Code, OpenCode, Mistral Vibe, Codex CLI, Gemini CLI, Cursor CLI) inside isolated Docker containers while maintaining access to your project files and credentials.
66

77
**Key Features:**
88
- One container per session
@@ -84,7 +84,7 @@ environment = ["ANTHROPIC_API_KEY"]
8484

8585
### Shared Agent Config Directories
8686

87-
AOE shares your host agent credentials with sandboxed containers so agents can authenticate without re-login. This works for all supported agents: Claude Code, OpenCode, Codex, Gemini, and Vibe.
87+
AOE shares your host agent credentials with sandboxed containers so agents can authenticate without re-login. This works for all supported agents: Claude Code, OpenCode, Codex, Gemini, Vibe, and Cursor.
8888

8989
Rather than bind-mounting your actual host config directories (which would let container writes modify your host files), AOE creates a **shared sandbox directory** per agent:
9090

@@ -187,7 +187,7 @@ AOE provides two official sandbox images:
187187

188188
| Image | Description |
189189
|-------|-------------|
190-
| `ghcr.io/njbrake/aoe-sandbox:latest` | Base image with Claude Code, OpenCode, Mistral Vibe, Codex CLI, Gemini CLI, git, ripgrep, fzf |
190+
| `ghcr.io/njbrake/aoe-sandbox:latest` | Base image with Claude Code, OpenCode, Mistral Vibe, Codex CLI, Gemini CLI, Cursor CLI, git, ripgrep, fzf |
191191
| `ghcr.io/njbrake/aoe-dev-sandbox:latest` | Extended image with additional dev tools |
192192

193193
### Dev Sandbox Tools
@@ -212,7 +212,7 @@ default_image = "ghcr.io/njbrake/aoe-dev-sandbox:latest"
212212

213213
## Custom Docker Images
214214

215-
The default sandbox image includes Claude Code, OpenCode, Mistral Vibe, Codex CLI, Gemini CLI, git, and basic development tools. For projects requiring additional dependencies beyond what the dev sandbox provides, you can extend either base image.
215+
The default sandbox image includes Claude Code, OpenCode, Mistral Vibe, Codex CLI, Gemini CLI, Cursor CLI, git, and basic development tools. For projects requiring additional dependencies beyond what the dev sandbox provides, you can extend either base image.
216216

217217
### Step 1: Create a Dockerfile
218218

docs/quick-start.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ aoe add -c opencode .
6868
aoe add -c vibe .
6969
aoe add -c codex .
7070
aoe add -c gemini .
71+
aoe add -c cursor .
7172
```
7273

7374
In the TUI, select the tool from the dropdown in the new session dialog.

src/agents.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ pub const AGENTS: &[AgentDef] = &[
110110
detect_status: status_detection::detect_gemini_status,
111111
container_env: &[],
112112
},
113+
AgentDef {
114+
name: "cursor",
115+
binary: "agent",
116+
aliases: &[],
117+
detection: DetectionMethod::Which("agent"),
118+
yolo: Some(YoloMode::CliFlag("--yolo")),
119+
instruction_flag: None,
120+
set_default_command: false,
121+
supports_host_launch: true,
122+
detect_status: status_detection::detect_cursor_status,
123+
container_env: &[],
124+
},
113125
];
114126

115127
/// Look up an agent by canonical name.
@@ -174,6 +186,7 @@ mod tests {
174186
assert_eq!(get_agent("vibe").unwrap().binary, "vibe");
175187
assert_eq!(get_agent("codex").unwrap().binary, "codex");
176188
assert_eq!(get_agent("gemini").unwrap().binary, "gemini");
189+
assert_eq!(get_agent("cursor").unwrap().binary, "agent");
177190
}
178191

179192
#[test]
@@ -184,7 +197,10 @@ mod tests {
184197
#[test]
185198
fn test_agent_names() {
186199
let names = agent_names();
187-
assert_eq!(names, vec!["claude", "opencode", "vibe", "codex", "gemini"]);
200+
assert_eq!(
201+
names,
202+
vec!["claude", "opencode", "vibe", "codex", "gemini", "cursor"]
203+
);
188204
}
189205

190206
#[test]
@@ -194,19 +210,23 @@ mod tests {
194210
assert_eq!(resolve_tool_name("mistral-vibe"), Some("vibe"));
195211
assert_eq!(resolve_tool_name("codex"), Some("codex"));
196212
assert_eq!(resolve_tool_name("gemini"), Some("gemini"));
213+
assert_eq!(resolve_tool_name("cursor"), Some("cursor"));
197214
assert_eq!(resolve_tool_name(""), Some("claude"));
198215
assert_eq!(resolve_tool_name("unknown-tool"), None);
216+
assert_eq!(resolve_tool_name("agent"), None);
199217
}
200218

201219
#[test]
202220
fn test_settings_index_roundtrip() {
203221
assert_eq!(settings_index_from_name(None), 0);
204222
assert_eq!(settings_index_from_name(Some("claude")), 1);
205223
assert_eq!(settings_index_from_name(Some("gemini")), 5);
224+
assert_eq!(settings_index_from_name(Some("cursor")), 6);
206225

207226
assert_eq!(name_from_settings_index(0), None);
208227
assert_eq!(name_from_settings_index(1), Some("claude"));
209228
assert_eq!(name_from_settings_index(5), Some("gemini"));
229+
assert_eq!(name_from_settings_index(6), Some("cursor"));
210230
assert_eq!(name_from_settings_index(99), None);
211231
}
212232

src/cli/add.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub struct AddArgs {
2222
#[arg(short = 'g', long)]
2323
group: Option<String>,
2424

25-
/// Command to run (e.g., 'claude', 'opencode', 'vibe', 'codex', 'gemini')
25+
/// Command to run (e.g., 'claude', 'opencode', 'vibe', 'codex', 'gemini', 'cursor')
2626
#[arg(short = 'c', long = "cmd")]
2727
command: Option<String>,
2828

src/tmux/status_detection.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,10 @@ pub fn detect_codex_status(raw_content: &str) -> Status {
403403
Status::Idle
404404
}
405405

406+
pub fn detect_cursor_status(content: &str) -> Status {
407+
detect_claude_status(content)
408+
}
409+
406410
pub fn detect_gemini_status(raw_content: &str) -> Status {
407411
let content = raw_content.to_lowercase();
408412
let lines: Vec<&str> = content.lines().collect();
@@ -704,6 +708,44 @@ mod tests {
704708
assert_eq!(detect_codex_status("random output text"), Status::Idle);
705709
}
706710

711+
#[test]
712+
fn test_detect_cursor_status_running() {
713+
assert_eq!(
714+
detect_cursor_status("Working on your request (esc to interrupt)"),
715+
Status::Running
716+
);
717+
assert_eq!(detect_cursor_status("Processing ⠋"), Status::Running);
718+
}
719+
720+
#[test]
721+
fn test_detect_cursor_status_waiting() {
722+
assert_eq!(detect_cursor_status("Yes, allow once"), Status::Waiting);
723+
assert_eq!(detect_cursor_status("Task complete.\n>"), Status::Waiting);
724+
}
725+
726+
#[test]
727+
fn test_detect_cursor_status_idle() {
728+
assert_eq!(detect_cursor_status("some random output"), Status::Idle);
729+
}
730+
731+
#[test]
732+
fn test_detect_cursor_status_delegates_to_claude() {
733+
// Cursor CLI is built on Claude Code, so all Claude patterns should work
734+
let test_cases = vec![
735+
("Thinking... · esc to interrupt", Status::Running),
736+
("Do you trust the files in this folder?", Status::Waiting),
737+
("completed the task", Status::Idle),
738+
];
739+
for (content, expected) in test_cases {
740+
assert_eq!(
741+
detect_cursor_status(content),
742+
expected,
743+
"Failed for: {}",
744+
content
745+
);
746+
}
747+
}
748+
707749
#[test]
708750
fn test_detect_gemini_status_running() {
709751
assert_eq!(

src/tui/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub async fn run(profile: &str) -> Result<()> {
7070
eprintln!("Agent of Empires requires at least one of:");
7171
eprintln!(" claude - Anthropic's Claude CLI");
7272
eprintln!(" opencode - OpenCode CLI");
73+
eprintln!(" cursor - Cursor's Agent CLI");
7374
eprintln!();
7475
eprintln!("Install one of these tools and ensure it's in your PATH.");
7576
std::process::exit(1);

0 commit comments

Comments
 (0)