Add support for Cursor - #42
Conversation
There was a problem hiding this comment.
Pull request overview
Adds Cursor as a first-class supported harness (Cursor App via Team Marketplace plugin + Cursor CLI via file-based config), and updates repo docs/manifests to reflect the new distribution surface and required version/skill-doc lockstep.
Changes:
- Introduces Cursor plugin + marketplace manifests and Cursor-specific install docs/config (
cursor/+.cursor-plugin/). - Updates root documentation (README/CLAUDE/CONTRIBUTING) to include Cursor as a supported harness and document dual App/CLI paths.
- Bumps plugin versions and extends “version alignment” guidance to include Cursor.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Adds installation instructions for Cursor CLI and Cursor App plugin. |
| cursor/skills/outsystems/SKILL.md | Adds Cursor harness skill doc (agent rules/workflows) for plugin + CLI use. |
| cursor/README.md | Adds Cursor-specific setup guide and version/lockstep guidance. |
| cursor/mcp.json | Adds canonical Cursor CLI mcpServers configuration example. |
| cursor/.cursor-plugin/plugin.json | Adds Cursor plugin manifest (name/version/skills path). |
| CONTRIBUTING.md | Updates contribution docs for new Cursor distribution surfaces and lockstep requirements. |
| CLAUDE.md | Updates supported harness table and expands lockstep/version-alignment guidance to include Cursor. |
| .cursor-plugin/marketplace.json | Adds Cursor Team Marketplace index manifest pointing at cursor/. |
| .claude-plugin/plugin.json | Bumps Claude plugin version. |
| .claude-plugin/marketplace.json | Bumps Claude marketplace plugin version. |
Suppressed comments (3)
cursor/README.md:68
- This line says “Update all three together”, but there are four version fields that must be kept in sync (Claude plugin + marketplace, Cursor plugin + marketplace).
Update all three together in the same commit when bumping the version.
CLAUDE.md:60
- The lockstep grep loop includes
cursor/skill.md, which doesn’t exist in the repo; the Cursor doc path iscursor/skills/outsystems/SKILL.md. As written, the check will fail or silently miss Cursor changes.
for f in skills/outsystems/SKILL.md kiro/outsystems/steering/skill.md copilot/skill.md cursor/skill.md SKILL.md; do
CLAUDE.md:73
- This sentence references
cursor/skill.md, but the Cursor skill doc iscursor/skills/outsystems/SKILL.md. Keeping the correct path here matters for the “host-specific affordances” exception.
Host-specific UI surfaces (typed shortcuts, hotkeys) live only in the doc for the host that has them. The Claude Code marketplace plugin ships slash commands under `commands/` (declared in `.claude-plugin/plugin.json`'s `commands` key); Kiro Powers do not have an equivalent. So mentions of `/outsystems-feedback` and similar slash-command trigger phrases belong only in `skills/outsystems/SKILL.md`, not in `kiro/outsystems/steering/skill.md`, `copilot/skill.md`, `cursor/skill.md`, or root `SKILL.md`. The underlying *behavior* (what the agent does on the trigger) still has to lockstep across all five docs.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
david-santos-os
left a comment
There was a problem hiding this comment.
Nice work overall — the structure is right: the ## Rules section is byte-identical across all five skill docs, the slash-command mentions are correctly stripped from the Cursor doc, and all four manifests land on 0.13.0 together. I left the blockers and the smaller fixes as inline comments. The short version: the new skill doc was forked from a pre-0.12.0 revision of the shared content and needs a re-sync, and a few paths/URLs in the docs don't match the files the PR actually ships.
Three things I couldn't verify from the diff and would like confirmed before merge:
-
Is the CLI binary really
agent? Every CLI instruction here usesagent mcp list/agent mcp enable/agent mcp login, but Cursor's CLI installs ascursor-agent. If the name is wrong, every CLI step in README.md, CONTRIBUTING.md, and cursor/README.md fails. Please confirm on a current install and note the version you tested with. -
Is
.cursorrulesstill the right target? It's Cursor's legacy rules mechanism, superseded by.cursor/rules/and AGENTS.md support. Before we standardize on it across three docs, worth confirming the CLI actually loads it today. -
Can you record an end-to-end run for both new harness rows? Per CLAUDE.md's validate-every-harness policy: a Team Marketplace import for the app path, and
agent mcp list→ OAuth → a real tool call for the CLI path. The PR notes the structure matches rd-ai-common#33, but a couple of the inline findings (the 404 in the install prompt, the missing frontmatter) are exactly the kind of thing an e2e run would have caught.
One more small thing: the PR description has drifted from the diff — it says 0.11.0 → 0.12.0 (the diff is 0.12.1 → 0.13.0), the new-files list is missing cursor/mcp.json, and the validation section says "all 6 skill docs" where there are five. Worth updating so the merge record is accurate.
Yes, the correct command is
Fixed.
e2e was done in a session with David. |
david-santos-os
left a comment
There was a problem hiding this comment.
All the previous findings are addressed — I re-verified rather than took it on faith: every shared section of the Cursor doc now hashes identical to the Kiro doc (builder_retry_friction, the revision-notes caveat, and the explicit publish recipe included), the frontmatter is in, the lockstep grep runs against real paths, the raw URL resolves, and the version lists, counts, and numbering are all correct. Thanks for the quick turnaround, and for the answers on the CLI binary and the e2e run.
The remaining asks are about the new callback-troubleshooting content that came in with 724375d. It's a good addition, but the "extract the authorization code" advice only works on the one host that has a tool to accept a pasted code (Claude Code's complete_authentication), and in the Cursor doc it contradicts the same section it lives in. Details inline — they're wording-level fixes, plus one .cursorrules straggler.
Two non-code asks:
-
One more pass on the PR description, please. It still says
.cursorrulesin the skill-doc structure section and "All 6 skill docs" / "synchronized to 0.12.0" under Validation — and it doesn't mention the callback-troubleshooting guidance or thecopilot/skill.mdfrontmatter at all, which are real behavioral changes shipping in this PR. It's the merge record; it should describe what's actually landing. -
Is the frontmatter added to
copilot/skill.mdintentional? That file is copied verbatim into.github/copilot-instructions.md, which is plain markdown — the YAML block will show up as literal content in every Copilot user's instructions file. If it's there for AGENTS.md tooling or a Copilot feature I'm missing, a line in the PR description would help; if not, it can be dropped (rootSKILL.mddidn't get one either).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.
Suppressed comments (10)
cursor/skills/outsystems/SKILL.md:67
- A refused TCP callback happens before Cursor's listener or the token endpoint receives the code, so it does not itself spend the code. This contradicts the preceding
curlreplay of the identical callback and can trigger needless reauthentication. Only start fresh if that replay reports an ended/expired session or redemption failure.
**If the browser shows "site can't be reached" at the callback URL:** The sign-in already succeeded on the tenant side — the identity provider issued the code and redirected. Only the last local hop failed: Cursor's callback listener and the browser's redirect resolved to different addresses, typically an IPv4/IPv6 loopback mismatch in a VM, where the listener is on `[::1]:PORT` and the redirect went to `127.0.0.1:PORT`. **Do not wait for the timeout, and tell the user so immediately** — they don't need to sit through the two-minute failure. Ask the user for the full URL from the address bar (it contains `callback?state=...&code=...`), then **complete the callback yourself via the terminal**: find the port Cursor is listening on with `lsof -nP -iTCP -sTCP:LISTEN | grep LISTEN` and look for the port in the URL. Re-send the identical callback to Cursor's listener with `curl "http://[::1]:PORT/callback?state=...&code=..."`, swapping the host to `[::1]` if the address bar showed `127.0.0.1`. This hand-off is not an auth tool call; it simply delivers the code to Cursor's loopback listener where the redirect was meant to land. The code is single-use, so do not also ask the user to retry in the browser — one of you, not both. **Expect the attempt to be dead already:** the refused connection tears down the authorization session, so you'll likely get "Authorization session ended" and that code is spent. If so, ask the user to start a fresh sign-in and tell them the corrected address (`[::1]` instead of `127.0.0.1`) to use *before* they click through. Treat authorization codes as credentials either way.
copilot/skill.md:43
- A refused TCP callback happens before Copilot CLI's listener or the token endpoint receives the code, so it does not itself spend the code. This contradicts the preceding
curlreplay of that same callback and can trigger needless reauthentication. Only start fresh if replay reports an ended/expired session or redemption failure.
- **Copilot CLI** runs the OAuth flow on the first tool call (opens the system browser and listens on an ephemeral `localhost` port for the callback). A browser must be reachable on the same machine. If the browser shows "site can't be reached" at the callback URL (typically an IPv4/IPv6 loopback mismatch in a VM): **do not wait for timeout, and tell the user immediately** — tenant-side sign-in already succeeded. Ask the user for the full URL from the address bar. Complete the callback yourself via the terminal: find the port from the URL and run `lsof -nP -iTCP -sTCP:LISTEN | grep LISTEN` to confirm the listener. Re-send the callback with `curl "http://[::1]:PORT/callback?state=...&code=..."`, swapping the host to `[::1]` if the URL showed `127.0.0.1`. This delivers the code to Copilot CLI's loopback listener, not a tool call. Do not also ask the user to retry in the browser. **Expect the code to be spent:** the refused connection tears down the auth session. If you get "Authorization session ended", have the user start fresh with the corrected address before clicking through. Treat authorization codes as credentials.
cursor/README.md:3
- The plugin is only the Cursor App distribution path; the CLI path in this directory is a manual MCP config plus a copied skill file. Saying the plugin is available for CLI conflicts with the installation sections below.
This directory ships the OutSystems MCP plugin for Cursor, available for both Cursor app and Cursor CLI.
cursor/skills/outsystems/SKILL.md:17
- This setup is not universally a two-stage flow: Cursor CLI users do not install the Team Marketplace plugin, as the CLI section below confirms. Present App and CLI as alternative paths so CLI users are not told that an admin/plugin install is a prerequisite.
This issue also appears on line 67 of the same file.
The OutSystems MCP server registration happens in two stages:
1. **Team admin adds the plugin** (via Dashboard → Plugins → Team Marketplaces → Import from Repo)
2. **Individual user completes setup** via agent prompts in Cursor app or CLI
CLAUDE.md:47
- This omits the primary automatic consumer introduced by the PR: Cursor App loads this document through the plugin manifest, while Cursor CLI consumes a manual copy. Document both paths to keep the canonical harness table and this list consistent.
- `cursor/skills/outsystems/SKILL.md` is the Cursor skill doc, consumed by Cursor CLI.
SKILL.md:15
- The new generic skill has no harness-specific authentication subsections, so this reference sends fallback-client users to instructions that do not exist in the document. Point readers to their client's authentication documentation instead.
**If the browser shows "site can't be reached" at the callback URL:** The sign-in succeeded on the tenant side — only the callback connection failed, typically an IPv4/IPv6 loopback mismatch in a VM. **Do not make the user wait for timeout; tell them immediately.** Ask for the full callback URL from the address bar. Recovery depends on your harness: some clients can replay the callback via shell commands; others require the user to adjust the address in their browser. See your harness's specific Authenticating section for the exact steps. Treat authorization codes as credentials — code is single-use and short-lived.
copilot/skill.md:43
- The PR description and validation state that YAML
name/descriptionfrontmatter was added here, but this file still starts directly with# OutSystems - Remote MCPat line 1; this callback edit is the only current change. Add the promised frontmatter or correct the stated scope.
This issue also appears on line 43 of the same file.
- **Copilot CLI** runs the OAuth flow on the first tool call (opens the system browser and listens on an ephemeral `localhost` port for the callback). A browser must be reachable on the same machine. If the browser shows "site can't be reached" at the callback URL (typically an IPv4/IPv6 loopback mismatch in a VM): **do not wait for timeout, and tell the user immediately** — tenant-side sign-in already succeeded. Ask the user for the full URL from the address bar. Complete the callback yourself via the terminal: find the port from the URL and run `lsof -nP -iTCP -sTCP:LISTEN | grep LISTEN` to confirm the listener. Re-send the callback with `curl "http://[::1]:PORT/callback?state=...&code=..."`, swapping the host to `[::1]` if the URL showed `127.0.0.1`. This delivers the code to Copilot CLI's loopback listener, not a tool call. Do not also ask the user to retry in the browser. **Expect the code to be spent:** the refused connection tears down the auth session. If you get "Authorization session ended", have the user start fresh with the corrected address before clicking through. Treat authorization codes as credentials.
CLAUDE.md:60
- The supported-harness expansion leaves
.github/pull_request_template.md:16-19stale: it still lists only Claude Code/Kiro/Copilot, four skill docs, and the two Claude manifests. Future PRs following that checklist can therefore skip Cursor validation and the new five-doc/four-manifest lockstep requirements documented here.
After any skill-doc change, grep for a distinctive phrase from the change across all five files and confirm the count matches:
```bash
PHRASE="<a distinctive substring from your change>"
for f in skills/outsystems/SKILL.md kiro/outsystems/steering/skill.md copilot/skill.md cursor/skills/outsystems/SKILL.md SKILL.md; do
skills/outsystems/SKILL.md:40
- A refused TCP callback happens before the listener or token endpoint receives the authorization code, so the refusal does not itself spend the code. This contradicts the recovery immediately above that forwards the same callback URL and can cause an unnecessary second sign-in. Only require a fresh flow after replay actually reports an ended/expired session or redemption failure.
- **Remote session** (callback page fails to load, e.g. SSH / devcontainer, or "site can't be reached" in a VM): **do not wait for timeout, and tell the user immediately** — tenant-side sign-in already succeeded; they don't need to sit through the two-minute failure. Ask the user to copy the full URL from their browser's address bar (`http://localhost:<port>/callback?code=...&state=...`), then call `mcp__outsystems__complete_authentication { callback_url: "<that URL>" }` to deliver the code to Claude Code's callback listener. This completes the sign-in flow. The authorization code is single-use, so if it fails, start a fresh `mcp__outsystems__authenticate` and do not ask the user to also retry in the browser. **Expect the code to be spent:** if the callback connection was refused, the authorization session was torn down and that code is no longer valid. If you get a "session ended" error, ask the user to start a fresh sign-in. Treat authorization codes as credentials either way.
kiro/outsystems/steering/skill.md:45
- A refused TCP callback happens before Kiro's listener or the token endpoint receives the code, so it does not itself spend the code. This also contradicts the preceding instruction to retry that same URL with the corrected host. Start a fresh flow only when the corrected callback actually returns an ended/expired session or redemption failure.
**If the browser shows "site can't be reached" at the callback URL:** The sign-in already succeeded on the tenant side — the identity provider issued the code and redirected. Only the last local hop failed: Kiro's callback listener and the browser's redirect resolved to different addresses, typically an IPv4/IPv6 loopback mismatch in a VM, where the listener is on `[::1]:PORT` and the redirect went to `127.0.0.1:PORT`. **Do not wait for the timeout, and tell the user immediately** — they don't need to sit through the two-minute failure. Ask the user to adjust the address in their own browser: if the address bar shows `http://127.0.0.1:PORT/callback?state=...&code=...`, they should change just the host to `[::1]` (keeping the square brackets and the entire rest of the URL), then press Enter. This routes the callback to Kiro's IPv6 loopback where it's actually listening. Do not ask them to also retry after — one attempt, not both. **Expect the code to be spent:** the refused connection tears down the authorization session. If it answers "Authorization session ended", start a fresh sign-in and give them the corrected address *before* they click through. Treat authorization codes as credentials either way.
david-santos-os
left a comment
There was a problem hiding this comment.
Re-verified the latest round: the callback recovery guidance is now actionable on every host (and honest about the code usually being spent), the CLI reactive path is back, the .cursorrules straggler is gone, and all shared sections still hash identical across the five skill docs with the manifests aligned on 0.13.0. Good to go — thanks for the thorough turnaround across all three rounds.
Add Cursor as a first-class supported harness with plugin-based app support and CLI support
Changes
New Files
.cursor-plugin/marketplace.json— Cursor Team Marketplace index for plugin distributioncursor/.cursor-plugin/plugin.json— Cursor plugin manifest (name, version, skills)cursor/skills/outsystems/SKILL.md— Agent guidance doc (plugin-shipped, used by both app and CLI)cursor/README.md— Install instructions for both Cursor App (plugin) and Cursor CLIcursor/mcp.json— Canonical Cursor CLI MCP server configuration templateModified Files
README.md— Added Cursor CLI (all plans) and Cursor App (Team/Enterprise plugin) install sections; updated.cursorrulesreferences to.cursor/rules/outsystems.mdwithAGENTS.mdfallbackCLAUDE.md— Updated harness table with two Cursor rows (App + CLI); documented plugin/CLI dual paths and version lockstep (all 4 manifest files)CONTRIBUTING.md— Updated repository structure, prerequisites, and testing sections; added plugin version alignment requirements; updated CLI config references to.cursor/rules/copilot/skill.md— Added YAML frontmatter (name: outsystems, description) for consistency with plugin-shipped skill docsskills/outsystems/SKILL.md,kiro/outsystems/steering/skill.md,copilot/skill.md,cursor/skills/outsystems/SKILL.md,SKILL.md— Added callback-failure troubleshooting guidance (connection-refused in VMs, don't wait for timeout, ask user for URL, IPv4→IPv6 adjustment).claude-plugin/plugin.json— Bumped 0.12.0 → 0.13.0.claude-plugin/marketplace.json— Bumped 0.12.0 → 0.13.0cursor/.cursor-plugin/plugin.json— Version 0.13.0 (new).cursor-plugin/marketplace.json— Version 0.13.0 (new)Details
Cursor CLI (All Plans)
~/.cursor/mcp.json(global) or.cursor/mcp.json(project)mcpServers(notservers){"mcpServers": {"outsystems": {"url": "https://..."}}}— notypefieldagent mcp loginandagent mcp enableCLI commandscursor/skills/outsystems/SKILL.mdand save to.cursor/rules/outsystems.md(orAGENTS.mdif project uses that)Cursor App (Team/Enterprise Plan Plugin)
~/.cursor/mcp.json)Plugin Version Alignment
.claude-plugin/plugin.json→version.claude-plugin/marketplace.json→plugins[0].versioncursor/.cursor-plugin/plugin.json→version.cursor-plugin/marketplace.json→plugins[0].versionSkill Doc Updates
copilot/skill.md— Added YAML frontmatter for consistency with plugin-shipped skill docs127.0.0.1to[::1])Validation
## Rules,## Workflows,## Feedbacksections.cursor/rules/instead of.cursorrules