Skip to content

refactor(registry/coder-labs/modules/cursor-cli)!: remove agentapi, tasks and start logic - #1152

Open
35C4n0r wants to merge 10 commits into
mainfrom
35C4n0r/migrate-cursor-cli
Open

35C4n0r wants to merge 10 commits into
mainfrom
35C4n0r/migrate-cursor-cli

Conversation

@35C4n0r

@35C4n0r 35C4n0r commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

Closes REG-84

Refactor coder-labs/cursor-cli to install and configure Cursor CLI only, matching the codex v5 and copilot (#1117) migrations.

  • Replace the agentapi module with coder-utils; drop Tasks inputs (order, group, install_agentapi, agentapi_version, ai_prompt), the start script, and the task-reporting coder MCP server.
  • Install via the official installer (https://cursor.com/install, temp file + bash -n validation, retrying curl). Skipped when cursor-agent is already on PATH; fails clearly when install_cursor_cli = false and no binary exists.
  • Rename required folder to optional workdir; create it and write Cursor's workspace trust marker so the trust prompt is skipped.
  • Merge mcp into user-level ~/.cursor/mcp.json (existing on-disk servers win on duplicate names; invalid JSON is backed up to mcp.json.bak).
  • Keep rules_files (now requires workdir) and api_key (CURSOR_API_KEY, never rendered into the script).
  • Add cursor_config_dir (default ""): sets CURSOR_CONFIG_DIR via coder_env only when non-empty, so an existing value is never overwritten. It moves cli-config.json only; Cursor CLI always reads the user-level mcp.json from ~/.cursor, so the module keeps writing mcp there (verified against the binary).
  • Remove model and force: Cursor CLI has no model env var, so both become --model / --force flags in the user's coder_app.
  • Add scripts output; rewrite README (v1 warning, launcher example) and tests. Bump to 1.0.0.

Important

The trust marker (${CURSOR_DATA_DIR:-~/.cursor}/projects/<slug>/.workspace-trusted) is derived from the CLI bundle, not public docs. The path matches what the CLI creates, but suppression of the prompt could not be verified end to end without a real Cursor API key (auth is checked before trust). Worth a manual check.

Decision log

Verified against the installed CLI (2026.09.26-dd393fe) and Cursor docs:

Skill pattern Cursor CLI reality Decision
Pass VERSION to official installer Installer bakes in the latest build; no version input No version variable
Model via documented env var No model env var; --model flag / /model only Drop model, document flag
managed_settings root-owned policy No general policy file; ~/.cursor/policy.json is sign-in enforcement only Not added
Native mcp add duplicate semantics No mcp add; config is .cursor/mcp.json or ~/.cursor/mcp.json jq merge into global file, existing wins
Workdir trust key in config Trust is a per-project marker file written by --trust or the prompt Write the same marker if absent
AI Gateway port Not present pre-migration Out of scope
Binary name Installer links agent (primary) and cursor-agent (legacy) Probe/link cursor-agent (unambiguous)

Testing

  • terraform validate, terraform test (8 passed)
  • bun test main.test.ts (14 passed, container-based)
  • Real installer run in codercom/enterprise-node via the rendered install script: installed, validated, workdir trusted, PATH updated
  • shellcheck on rendered install script, prettier, readmevalidation

Generated with Coder Agents.

…asks and start logic

Make cursor-cli an install-only module built on coder-utils. The user now
launches Cursor CLI with their own coder_app.

- Drop the agentapi module, Tasks inputs, start script and the
  task-reporting MCP server.
- Install via the official installer (temp file, bash -n validation).
- Rename folder to optional workdir; create it and write Cursor's
  workspace trust marker.
- Merge mcp into ~/.cursor/mcp.json with existing servers winning.
- Keep rules_files (requires workdir) and api_key (CURSOR_API_KEY).
- Remove model, force and ai_prompt in favor of launcher CLI flags.
- Add scripts output; rewrite README and tests; bump to 1.0.0.
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Module Scorecard Check

coder-labs/cursor-cli: first scorecard, 64 / 100

No specific score is required to contribute, but modules with higher scores are more likely to be approved by the Coder team and widely used.

Full scorecard for this PR
Presentation & Onboarding Agent Integration Credential Hygiene Restricted-Environment Readiness Engineering Quality Overall
12 / 17 10 / 25 20 / 20 7 / 20 10 / 10 64 / 100
Drilldown

Presentation & Onboarding — 12 / 17

Criterion Max Score Notes
Configuration-mode examples 12 12 README documents multiple major modes with sensible defaults: default headless install, "Standalone mode with a launcher app" (coder_app), "MCP servers and rules" (mcp/rules_files), and downstream coder_script chaining via the scripts output. Each shows working .tf snippets.
Visual preview 5 0 No image, GIF, or video anywhere in the README; only an icon reference in frontmatter.

Credential Hygiene — 20 / 20

Criterion Max Score Notes
Secrets marked sensitive 16 16 api_key variable is declared sensitive = true in main.tf. All README examples use api_key = var.cursor_api_key, never an inline literal key.
Non-hardcoded auth path 4 4 "Configuration" section documents an alternative to injecting a key: "run cursor-agent login in the workspace," and the API key is passed via coder_env rather than templated into scripts.

Restricted-Environment Readiness — 7 / 20

Criterion Max Score Notes
Mirrorable artifact source 5 0 The installer URL https://cursor.com/install is hardcoded in scripts/install.sh.tftpl with no variable to override it. No module input overrides the download URL.
Bring-your-own binary 10 5 install_cursor_cli = false skips install and requires a pre-baked cursor-agent on PATH (validated in ensure_cursor_in_path), extensively exercised in tests. However, this is never mentioned or exampled in the README — only present in the variable's inline description — so it is under-documented.
Egress transparency 3 0 No dedicated README section enumerating external endpoints (e.g., cursor.com/install). Not mentioned anywhere in the README at all.
Runs without sudo 2 2 scripts/install.sh.tftpl never invokes sudo; uses curl, mktemp, jq, user-space $HOME/.local/bin and shell profile edits only. Confirmed from source.

Engineering Quality — 10 / 10

Criterion Max Score Notes
Input quality 6 6 Variables have clear descriptions, sensible defaults (null, "", true, {}), and a validation block enforcing rules_files requires workdir.
Test coverage 4 4 main.tftest.hcl covers business logic (defaults, trimming, env var creation, validation failure, scripts ordering). main.test.ts covers extensive end-to-end container behavior (install paths, MCP merge/backup, trust marker, rules files, env var exposure).

Agent track — 10 / 25

Criterion Max Score Notes
AI governance 10 0 No mention of Coder AI Gateway or Agent Firewall anywhere in the README.
Dashboard entry point 5 5 README's "Standalone mode with a launcher app" example shows a full coder_app resource with icon, open_in, and launch command.
Session continuity 5 0 No documentation of session resume, reconnection, or a persistent session manager (tmux/screen/boo).
Managed configuration 5 5 mcp variable documents merging into ~/.cursor/mcp.json with existing-wins semantics, and rules_files documents writing to <workdir>/.cursor/rules/, both with a dedicated README example.

Overall — 64 / 100

Raw 59 / 92 → round(59 / 92 × 100) = 64

Tip

You can run this locally by telling your agent: "review this module against .github/scorecard/SCORECARD.md".


Scored against SCORECARD.md with solstice-1. Language-model scores are advisory.

@35C4n0r 35C4n0r changed the title refactor!: migrate coder-labs/cursor-cli off AgentAPI and Tasks refactor(registry/coder-labs/modules/cursor-cli)!: remove agentapi, tasks and start logic Sep 28, 2026
@35C4n0r
35C4n0r marked this pull request as ready for review October 12, 2026 05:16
@matifali

Copy link
Copy Markdown
Member

@codex review

@matifali matifali added the version:major Add to PRs requiring a major version upgrade label Oct 12, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-12T07:10:23.498243Z 61be2d3 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@matifali

Copy link
Copy Markdown
Member

Lets also allow passing arbitrary flags as extra-args or additional-args variables similar to some of or modules like code-server

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 61be2d3032

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

description = "Workspace-specific MCP JSON to write to folder/.cursor/mcp.json. See https://docs.cursor.com/en/context/mcp#using-mcp-json"
default = null
validation {
condition = var.mcp == "" || can(jsondecode(var.mcp).mcpServers)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Require mcpServers to be an object

When mcp is valid JSON but mcpServers is a string, number, or array, this validation succeeds because it only checks that the attribute can be accessed. Workspace startup then fails in setup_mcp_config when jq evaluates $custom + (.mcpServers // {}); for example, {"mcpServers":[]} causes an array/object addition error. Validate the field's object/map type so this configuration fails during planning instead.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

No longer applicable: the mcp validation block was removed in d5cc3ed along with the other non-essential validations. A non-object mcpServers still fails workspace startup with the jq merge error in setup_mcp_config, so a bad value surfaces at startup rather than at plan time.

Generated with Coder Agents.

}

locals {
workdir = var.workdir != null ? trimsuffix(var.workdir, "/") : ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve a root workdir during normalization

When a workspace intentionally uses / as its project directory, trimsuffix(var.workdir, "/") converts it to an empty string. The install script consequently skips directory trust setup, and if rules_files is configured it writes them under /.cursor/rules while treating the workdir as unset. Handle / specially or normalize trailing separators without erasing the root path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Not changed, intentionally. Using / as the project directory is an unusual edge case, and the normalization matches both the pre-migration module (trimsuffix(var.folder, "/")) and claude-code (trimsuffix(var.workdir, "/")). With workdir = "/", rules_files still lands in /.cursor/rules, which is the correct location for that workdir; only the directory trust entry is skipped.

Generated with Coder Agents.

…l variable validations

Drop the mcp shape and rules_files name checks. Keep the rules_files workdir requirement, since workdir is optional and rules are written under it.
@linear-code

linear-code Bot commented Oct 13, 2026

Copy link
Copy Markdown

REG-84

@coder

coder Bot commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Automated review requested by @matifali. Please sanity-check before acting on it.

CI and existing reviews

  • CI on the head sha is green, with the same job set as feat(registry/coder-labs/modules/copilot): migrate off AgentAPI and Tasks #1117. The Compare module scores against main check run shows in_progress, but the scorecard workflow finished (70/100).
  • The Codex bot left two P2 comments ("mcpServers must be an object" and "preserve root workdir"). The author replied to both, removing the validation and keeping the trimsuffix. Acceptable.
  • [SHOULD-FIX] Unanswered: matifali asked for an extra_args/additional_args variable. There's no reply and no change. Since v1 doesn't launch Cursor, flags belong in the user's coder_app (the README shows --model gpt-5 --force). The author should reply saying so, or agree on an alternative.

Correctness

The Terraform is coherent. required_version >= 1.9 is set, which the cross-variable rules_files validation needs. All variables are used, the unused workspace data sources and task_app_id were removed, and scripts was added. The install script is solid: retrying curl to a temp file, bash -n validation, --version check, a clear failure when install_cursor_cli=false and no binary exists, workdir creation, trust marker, MCP merge and rules files. api_key never appears in the script (there's a test for it).

[SHOULD-FIX] Stale v0 project-level mcp.json with the task-reporting server
v0 wrote <folder>/.cursor/mcp.json with a coder server pointing at /tmp/mcp-hack.sh. That script set CODER_MCP_APP_STATUS_SLUG and CODER_MCP_AI_AGENTAPI_URL=http://localhost:3284 and ran coder exp mcp server. v1 never touches the project file, so after an upgrade the stale entry stays in the user's repo, keeps failing to start, and could get committed.

Fix: when workdir is set, delete mcpServers.coder from <workdir>/.cursor/mcp.json if its command is /tmp/mcp-hack.sh, and remove the file if it ends up empty. At minimum, mention it in the README warning.

[SHOULD-FIX] Add nullable = false to mcp and rules_files
Both defaulted to null in v0, so templates often pass cond ? x : null. In v1, var.mcp != "" is true for null, so base64encode(null) errors at plan (main.tf:96), and length(null) errors in the rules_files validation (main.tf:72). With nullable = false, null falls back to the default.

[SHOULD-FIX / verify] The trust marker depends on undocumented CLI internals
install.sh.tftpl:139-165 writes ${CURSOR_DATA_DIR:-~/.cursor}/projects/<slug>/.workspace-trusted. The author says the path came from the CLI bundle and couldn't be verified end to end. Someone with a Cursor key should confirm the trust prompt is skipped. Describe it as best-effort in the README.

Leftovers

Breaking changes and migration

  • The README warning (README.md:22-23) is good. It covers dropping Tasks/AgentAPI, folder→workdir (now optional), model/force/ai_prompt moving to launcher flags, MCP moving to the user-level file, and "keep using v0.x.x".
  • [NIT] Not mentioned: the removed order, group, install_agentapi and agentapi_version; the removed task_app_id output; that v0 force defaulted to true (users must now add --force); and the stale project mcp.json cleanup. A short old→new list in the PR body, linked from the README like claude-code and codex v5, would cover all of these.

Tests

  • cursor-cli.tftest.hcl was renamed to main.tftest.hcl (8 runs: defaults, trim, api_key env and absence from the script, cursor_config_dir, the rules→workdir validation, scripts ordering). main.test.ts has 14 container tests, including the installer path with a curl stub, download failure, marker preservation, merge precedence, the invalid-JSON backup, and config dir isolation. Coverage is strong.
  • Gaps (nits): no test for a non-object mcpServers (it fails with a raw jq error), and no stale-coder-cleanup test (if that cleanup is added).

Consistency and other nits

  • The two PRs handle an unparseable MCP file differently. Here it's backed up and replaced (install.sh.tftpl:182-196), so hand-edited JSONC servers silently stop loading; copilot warns and skips. Pick one approach for the series. Skip-and-warn, or stripping comments, is safer.
  • Give the merge a readable error: ($custom | if type=="object" then . else error("mcp.mcpServers must be an object") end).
  • rules_files keys are used as filenames without checks. Add a validation that rejects / and ...
  • Variable attribute order (type before description, and sensitive before default on api_key) differs from AGENTS.md. The series does the same, so this is low priority.
  • The AI footer doesn't name the model.

@35C4n0r

35C4n0r commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator Author

Lets also allow passing arbitrary flags as extra-args or additional-args variables similar to some of or modules like code-server

@matifali With this change the module only installs and configures Cursor CLI; it no longer launches cursor-agent (no start script or coder_app), so there is nothing for launch flags to attach to. code-server takes extra_args because that module starts the process.

Flags now belong in the template's own launcher, which the README shows:

command = <<-EOT
  #!/usr/bin/env bash
  set -e
  cd "${local.cursor_workdir}"
  exec cursor-agent --model gpt-5 --force
EOT

So I'm not adding an extra_args variable here.

Generated with Coder Agents.

Copy link
Copy Markdown
Member

Makes sense. Thanks

@35C4n0r

35C4n0r commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the automated review. Its verdict is "approve with nits, no blockers", and nothing in it is blocking enough to change in this PR:

  • extra_args: answered above; launch flags belong in the template's coder_app now.
  • Stale v0 coder server in .cursor/mcp.json: the entry only points at /tmp/mcp-hack.sh (no secret in the file) and just fails to start; Cursor CLI keeps working. The same upgrade leftover applies across the series, so it is better handled consistently there.
  • nullable = false: mcp and rules_files now default to "" and {}, so this only matters when a template explicitly passes null.
  • Trust marker: path comes from the Cursor CLI bundle and is covered by tests; an end-to-end check needs a Cursor key.
  • Remaining items are nits.

@DevelopmentCats could you take a look when you get a chance?

Generated with Coder Agents.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

version:major Add to PRs requiring a major version upgrade

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants