Repository navigation
feat(cursor): update the Cursor edition for Cursor 3.27 - #60
Open
tmcfarlane wants to merge 21 commits into
Open
tmcfarlane wants to merge 21 commits into
tmcfarlane wants to merge 21 commits into
Conversation
Cursor 3.27 uses a subagent's name as its identifier and wants lowercase names, blocks a command when a permission hook prints keys outside its schema, and loads a plugin only from .cursor-plugin/plugin.json. - Agents take their file names as names, so Task(toph) matches exactly. Sokka and Iroh move from the hidden Opus 4.8 to claude-opus-5-5[effort=high], Zuko to gemini-4-argon, and Sokka is marked readonly. - guard-shell.sh prints only permission, user_message, and agent_message, and escapes its messages; scripts/test-cursor-hooks.sh checks both. - post-edit-lint.sh lints from CURSOR_PROJECT_DIR when Cursor sets it. - .cursor-plugin/plugin.json and hooks/hooks.json make the repository a Cursor plugin. The root plugin.json, which no tool read, is gone. - Two vendored skills get names that match their folders.
The README, VALIDATION.md, the E2E runbook, and the changelog now say the edition needs Cursor 3.27, installs as a local plugin by default, and uses the current model IDs. They replace the silent-fallback and project-only-hooks claims with what the 3.27 docs say, and mark the 3.27 rows as checked against the docs, with a live run still to do.
Cursor 3.27 has no file-based user rules, so copying orchestrator.mdc into ~/.cursor/rules/ never turned orchestration on. The default user scope now builds ~/.cursor/plugins/local/team-avatar/ from the plugin layout, moves the files an older install left in ~/.cursor/ into a timestamped backup folder, and removes the plugin on --uninstall. A file moves only when it is clearly ours: agents by name, commands by content, and skills by their bundled description. --project keeps writing .cursor/. scripts/test-install-sh.sh runs the installer against throwaway homes: fresh install, migration from the main-branch installer, uninstall, disable and enable, project scope, dry run, a second run, and remote mode.
Both installers list their skills by hand, and both lists left out crafting-effective-readmes. The edition shipped 20 of the 21 skills the README promises. The bash test now compares the installed skill folders with skills/ instead of checking a fixed count.
A user-scope uninstall reads the bundled skills to tell them apart from a user's own copies. Under set -e, a failed download stopped the script before it removed the plugin. It now removes the plugin, leaves old skill folders in place, and says why.
install.ps1 now does what install.sh does at user scope. It builds ~/.cursor/plugins/local/team-avatar/, moves the old ~/.cursor files into a backup folder, and removes the plugin on uninstall, offline included. scripts/test-install-ps1.ps1 covers a fresh install, migration from the main-branch installer, uninstall, disable and enable, project scope, dry run, and reruns. It also nests three Join-Path calls that passed three arguments. Windows PowerShell 5.1 rejects those, so a local checkout there fell back to downloading main.
The update answer says where an old install's files go, and the uninstall answer says what stays. The changelog lists the PowerShell installer, the installer tests, and the two fixes.
The migration matched file contents loosely, so it could move a user's own files. A command that said "apparently" matched appa, and any script in ~/.cursor/hooks/ whose second line mentioned a hook moved. Each rule now matches what earlier releases shipped: agent names in all three historical forms, character names as whole words, and the exact second line of each hook script. Hook scripts stay when ~/.cursor/hooks.json exists, because the user may run them. With --no-skills, install.sh now leaves the old skill folders, as install.ps1 already did.
Cursor on Windows runs hook commands through PowerShell, so the bash hook scripts would fail there, and failClosed would turn each failure into a blocked shell command. On Windows, install.ps1 now gives the plugin an empty hook config at user scope and skips .cursor/hooks.json at project scope.
No workflow ran the hook or installer suites. The new workflow runs all three on ubuntu-latest when the Cursor edition changes. The installer suites now build the old layout from the v0.4.2 tag instead of origin/main, which stops being the old layout once this branch merges. The PowerShell suite gains a remote-mode case served by a local HttpListener, and the hook suite checks that deny and ask replies carry both messages.
In a UTF-8 locale, sed can reject an invalid byte from a cut staged line, which would empty the reason in a deny message.
The install table pointed at folders the installer no longer writes, and the README asked users to approve a rule file that no longer exists. Model IDs and fallback behavior now cite the doc that states them, and two IDs are marked inferred. The hooks section says they are off on Windows and that the guard matches text in the command.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved migration, Windows hook handling, planning permissions, and platform-specific test failures block approval.
4 open issues
What changed in this PR
Updates the Cursor edition for Cursor 3.27 by packaging user-scope installations as a local plugin, while retaining the project-scoped layout.
Changes:
- Adds plugin packaging, legacy-file migration, and updated install/uninstall behavior.
- Updates agent identifiers, model routing, hook replies, and Windows hook handling.
- Adds installer and hook tests, Linux CI, and documentation for pending live validation.
| File | Description |
|---|---|
VALIDATION.md |
Records documented 3.27 behavior and pending live checks. |
skills/refactoring/SKILL.md |
Matches the skill name to its directory. |
skills/frontend-builder/SKILL.md |
Matches the skill name to its directory. |
scripts/test-install-sh.sh |
Adds Bash installer regression tests. |
scripts/test-install-ps1.ps1 |
Adds PowerShell installer regression tests. |
scripts/test-cursor-hooks.sh |
Checks guard decisions and JSON replies. |
rules/orchestrator.mdc |
Updates routed model identifiers. |
README.md |
Documents plugin installation, models, and hooks. |
plugin.json |
Removes the unused root manifest. |
install.sh |
Adds user plugin installation and legacy migration. |
install.ps1 |
Adds plugin migration and platform-specific hook handling. |
hooks/post-edit-lint.sh |
Switches lint execution to the workspace root. |
hooks/hooks.json |
Registers plugin-scoped hooks. |
hooks/guard-shell.sh |
Uses documented reply fields and escapes messages. |
docs/E2E-TEST.md |
Updates the live-validation runbook. |
CHANGELOG.md |
Summarizes the Cursor edition update. |
automations/recipes/issue-design-zuko.md |
Clarifies cloud hook scope in documentation. |
agents/zuko.md |
Normalizes the name and updates the Gemini model. |
agents/toph.md |
Normalizes the agent name. |
agents/sokka.md |
Updates name and model; enables read-only mode. |
agents/protocols/team-avatar.md |
Revises worker model-routing guidance. |
agents/momo.md |
Normalizes the agent name. |
agents/katara.md |
Normalizes the agent name. |
agents/iroh.md |
Normalizes the name and updates the Opus model. |
agents/appa.md |
Normalizes the agent name. |
agents/aang.md |
Normalizes the agent name. |
.github/workflows/validate-cursor-edition.yml |
Runs three validation suites on Linux. |
.cursor-plugin/plugin.json |
Declares the Cursor plugin and its components. |
Review effort: Balanced
Comment on lines
+598
to
+600
| if ($ON_WINDOWS) { | ||
| $configFiles = @($CONFIG_FILES | Where-Object { $_ -ne 'hooks.json' }) | ||
| Write-Host ' [skipped] hooks.json: the hooks are bash scripts, and Cursor runs hooks through PowerShell on Windows' -ForegroundColor Yellow |
| description: Strategic planning agent for complex projects. Always use for planning multi-step features, analyzing ambiguous requirements, and reviewing work plans. Operates in interview/consultant mode. Use proactively when tasks need decomposition before implementation. | ||
| model: claude-opus-4-8-thinking-high | ||
| model: claude-opus-5-5[effort=high] | ||
| readonly: true |
Comment on lines
+689
to
+692
| ours="$(grep -m1 '^description:' "${WORK_DIR}/skills/${skill}/SKILL.md" 2>/dev/null || true)" | ||
| theirs="$(grep -m1 '^description:' "${CURSOR_DIR}/${rel}/SKILL.md" 2>/dev/null || true)" | ||
| if [ -n "$ours" ] && [ "$ours" = "$theirs" ]; then | ||
| backup_old_file "$rel" |
Comment on lines
+327
to
+333
| $projExpected = @('rules/orchestrator.mdc', 'agents/protocols/team-avatar.md', 'hooks.json', 'permissions.json') | ||
| $projExpected += $AGENTS | ForEach-Object { "agents/${_}.md" } | ||
| $projExpected += $COMMANDS | ForEach-Object { "commands/${_}.md" } | ||
| $projExpected += $HOOKS | ForEach-Object { "hooks/${_}" } | ||
| $projMissing = @($projExpected | Where-Object { -not (Test-Path (Join-Path $pc $_)) }) | ||
| Assert-That 'project layout files present' ($projMissing.Count -eq 0) ($projMissing -join ', ') | ||
| Assert-That '.cursor/hooks.json uses .cursor/hooks/ paths' ((Get-Content (Join-Path $pc 'hooks.json') -Raw) -match '\.cursor/hooks/guard-shell\.sh') |
The installers called ~/.agents/skills/ a legacy location and said it was safe to delete. Cursor reads user skills from that folder, and other tools keep their skills there too, so deleting it would remove skills that have nothing to do with Team Avatar. The note now names the skills that share a bundled name and says Cursor loads both copies.
On Cursor CLI 2026.10.22, `cursor-agent models` lists Opus 5.5 only with the effort in the ID, such as claude-opus-5-5-high. The bracket form claude-opus-5-5[effort=high] was rejected as an unknown model on a Free account, as was the CLI's own bracket example, so the agents now use the listed ID. The docs record which IDs the CLI recognized.
On Cursor 3.27, an agent created a file containing `as any`, staged it, and committed it in a single shell command, and the commit went through. The guard's anti-pattern check reads what is staged before the command runs, so it never saw the file. The guard now denies a commit command that also stages files (git add, git stage, git commit -a or --all) and tells the agent to stage first and commit separately.
Cursor 3.27 loads Claude Code plugins as well as local ones. With both Team Avatar editions installed, Cursor CLI 2026.10.22 ran the Claude Code edition's aang, katara, sokka, iroh, and zuko in place of this edition's agents, so the Cursor edition's agents and model pins never ran. Both installers now detect a team-avatar entry in ~/.claude/plugins/installed_plugins.json and say how to keep one edition in Cursor: turn off Include Third-Party Plugins, Skills, and Other Configs, or uninstall one of the two.
A plugin hook starts in the plugin's folder, and a probe hook on Cursor CLI 2026.10.22 showed that beforeShellExecution sends an empty cwd when the shell call names no directory. The guard then ran its anti-pattern check outside the repository, found nothing staged, and let a commit with `as any` through. It now falls back to CURSOR_PROJECT_DIR, the workspace root Cursor sets for every hook. A live rerun blocked the same commit.
VALIDATION.md and the E2E runbook record what ran on Cursor desktop 3.27.12 and CLI 2026.10.22: the plugin loads fully, the agents run, two guard blocks hold, and the commit check works after its fixes. Model routing and auto-review stay unverified, because the account was on a Free plan and the CLI's print mode skips permissions.json.
Sokka's planning skill saves plans under plans/, and Cursor's readonly flag blocks every file edit, not only code. This branch had added readonly: true, which origin/main never set. Sokka's own instructions already forbid writing code. Copilot's review caught this.
The migration treated an old skill folder as Team Avatar's when its first description line matched the bundled copy. vercel-composition-patterns puts its description on the lines after `description:`, so any same-named skill matched and a user's own copy would have moved. Both installers now compare the description line with its indented continuation lines. Copilot's review caught this.
On Windows, install.ps1 skips .cursor/hooks.json, but a file left by an earlier install still runs the bash guard with failClosed and blocks shell commands. The installer now says so and leaves the file alone, since a project's hooks.json may be shared with teammates on macOS or Linux. The PowerShell suite's project checks now hold on Windows too. Copilot's review caught both.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Why
Cursor no longer reads user rules from files, so the default install, which copied the orchestration rule into
~/.cursor/rules/, doesn't turn Team Avatar on anymore. Cursor applies a rule to every project only through a plugin. Cursor 3.27 also pins down agent names, hook replies, and model IDs, and hides Opus 4.8, which two agents used.What changed
.cursor-plugin/plugin.json,hooks/hooks.json).install.shandinstall.ps1install the user scope as a local plugin in~/.cursor/plugins/local/team-avatar/. They move files an earlier installer wrote into~/.cursor/to a backup folder, and only files that match what a release shipped.--projectkeeps the.cursor/layout.name. Sokka and Iroh runclaude-opus-5-5-high, and Zuko runsgemini-4-argon.guard-shell.shreplies with only the documented fields, checks commits from the workspace root, and blocks a command that stages and commits in one go. On Windows,install.ps1leaves the bash hooks off.Scope
permissions.json.Blast Radius
Everyone who reruns the installer at user scope. Old copies in
~/.cursor/move to~/.cursor/team-avatar-backup-<timestamp>/, and nothing is deleted. The shell guard now runs in every project on macOS and Linux withfailClosed, so its rules reach more people. It blocksrm -rfon any absolute path, a force-push to a branch such asmaintenance, and a combined stage-and-commit, which agents then split in two. Project installs keep their layout.Verification
rm -rf, a force-push tomain, and, after its fixes, anas anycommit. Details are inVALIDATION.md.scripts/test-install-sh.sh: 161 passed (macOS, bash 3.2).scripts/test-install-ps1.ps1: 98 passed (PowerShell 7.5, arm64 Linux).scripts/test-cursor-hooks.sh: 14 passed. The new cases fail against the code they fix.