Skip to content
Ultracite
Esc
↑↓navigate↵open⌘Jpreview

Oxlint in Cursor, on save and after agent edits

ultracite init --editors cursor writes .vscode/settings.json, so Cursor formats on save and applies your linter’s safe fixes, and installs the extension from Open VSX with the cursor launcher. Cursor’s agent applies AGENTS.md as a rule and reads linter errors to fix issues. --hooks cursor adds an afterFileEdit hook that fixes each file the agent edits, but nothing the hook prints reaches the agent.

Cursor by AnysphereChecked against Cursor 3.24

{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnPaste": true,
  "editor.formatOnSave": true,Format on save
  "emmet.showExpandedAbbreviation": "never",
  "js/ts.tsdk.path": "node_modules/typescript/lib",The project’s TypeScript
  "js/ts.tsdk.promptToUseWorkspaceVersion": true,
  "[astro]": {
    "editor.defaultFormatter": "astro-build.astro-vscode"
  },
  "[css]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[graphql]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[handlebars]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[html]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[javascript]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[javascriptreact]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[json]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[less]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[markdown]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[scss]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[typescript]": {Oxfmt formats it
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[vue-html]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[vue]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "[yaml]": {
    "editor.defaultFormatter": "oxc.oxc-vscode"
  },
  "editor.codeActionsOnSave": {
    "source.fixAll.oxc": "explicit"Oxlint’s safe fixes
  }
}
Oxlint + Oxfmt
What init does in Cursor
  1. 1Writes .vscode/settings.jsonA new file, or merged into yours setting by setting, with your comments and other settings kept.
  2. 2Installs oxc.oxc-vscodeWith cursor --install-extension, when it creates the settings file.
  3. 3With --hooks cursor, writes .cursor/hooks.jsonRuns npx ultracite fix --hook on each file Cursor’s agent edits.
Then, in Cursor
  1. 4If init couldn’t run cursor, install the Oxc extension from the Extensions view (Cmd+Shift+X), or Biome’s if you picked Biome.
  2. 5With --hooks cursor, open Customize → Hooks and check that afterFileEdit is listed.
  3. 6Save a file: Oxfmt formats it and Oxlint’s safe fixes apply.

Three toolchains, one settings.json

init writes the settings for the toolchain you pick, so Cursor formats with the same tool as ultracite fix and applies its fixes when you save.

  • Oxlint + OxfmtDefault

    Extension
    oxc.oxc-vscode
    Formats with
    oxc.oxc-vscode
    On save
    source.fixAll.oxc

    --linter oxlint

  • Biome

    Extension
    biomejs.biome
    Formats with
    biomejs.biome
    On save
    source.fixAll.biomesource.organizeImports.biome

    --linter biome

  • ESLint + Prettier + Stylelint

    Extensions
    dbaeumer.vscode-eslintesbenp.prettier-vscode
    Formats with
    esbenp.prettier-vscode
    On save
    source.fixAll.eslintsource.organizeImports

    --linter eslint

Where Cursor gets its extensions

Cursor reads .vscode/settings.json as VS Code does, but installs extensions from Open VSX through its own proxy, and team admins can restrict which ones install.

Extensions
From Open VSX, through Cursor’s own proxy (marketplace.cursorapi.com), which scans each extension before offering it. oxc.oxc-vscode, biomejs.biome, dbaeumer.vscode-eslint and esbenp.prettier-vscode are all there.
Launcher
cursor, which takes --install-extension like VS Code’s code. On macOS, Shell Command: Install 'cursor' command puts it on your PATH.
Workspace settings
Cursor is built on VS Code and reads .vscode/settings.json. The agent asks for your approval before it edits workspace settings.
Workspace trust
Off by default, so the settings apply as soon as you open a folder. If you turn it on with security.workspace.trust.enabled, Restricted Mode breaks AI features and project hooks wait for trust.
Team controls
Admins can limit installs to approved publishers or extension IDs (AllowedExtensions) and set an install cooldown for new versions. Either can block or delay the extension init installs.
Hooks
Cursor reloads .cursor/hooks.json when it changes. The Hooks tab in Customize and the Hooks output channel show what ran and any errors.

The hook fixes, the agent reads the lints

Cursor merges every rule that applies, team rules first, then project rules, then user rules, and AGENTS.md counts as a project rule with no frontmatter. Since 0.44 the agent reads linter errors to fix issues. The afterFileEdit hook from --hooks cursor fixes and formats each file the agent edits, but Cursor defines no output for that event, so the agent never sees what the hook printed.

Where the agent looks for instructions
  1. 1Team rulesSet in the dashboard on Team and Enterprise plans. They take precedence, and enforced ones can’t be turned off.
  2. 2.cursor/rules/*.mdcProject rules, applied by their alwaysApply, globs or description frontmatter. A plain .md file here is ignored.
  3. 3AGENTS.mdUltracitePlain Markdown at the project root, applied as a rule without frontmatter. This is where init writes Ultracite’s rules.
  4. 4CLAUDE.mdRead the same way as AGENTS.md, and applied to every conversation.
  5. 5frontend/AGENTS.mdApplied when the agent works on files in that folder, combined with the parent files; the more specific one wins.
  6. 6User rulesYour own rules from Customize → Rules, or files in ~/.cursor/rules. Lowest precedence.
{
  "hooks": {
    "afterFileEdit": [
      {
        "command": "npx ultracite fix --hook"
      }
    ]
  },
  "version": 1
}
init --hooks cursor
  1. 01The agent edits a file and writes it to disk, and Cursor fires afterFileEdit with the file’s path.
  2. 02npx ultracite fix --hook fixes and formats that one file. If problems remain, the hook fails; Cursor logs it in the Hooks output channel and the agent carries on.
  3. 03The Oxc, Biome or ESLint extension reports what’s left as linter errors, as it does for your own edits.
  4. 04The agent reads those linter errors and fixes what it can, so the lint loop runs through the editor, not the hook.
Agent pageUltracite for Cursor CLI

Worth knowing about Cursor

  • Tab edits skip the hook

    Cursor fires afterTabFileEdit for Tab completions and afterFileEdit only for the agent, so Ultracite’s hook doesn’t touch what you accept from Tab. Format on save covers those edits when you save the file.

  • Claude Code hooks run too

    With Third-Party Imports on, the default, Cursor also loads hooks from .claude/settings.json and runs every matching hook from every source. A project set up with --hooks claude as well as --hooks cursor can run Ultracite twice after one edit.

  • Cloud agents keep the hook

    Cloud agents run the command hooks in your repository’s .cursor/hooks.json, afterFileEdit included. They skip hooks during early read-only turns and start running them once the agent has a writable environment.

Cursor questions, answered

How do I format on save with Oxlint in Cursor?
Run npx ultracite init --editors cursor. It writes .vscode/settings.json with Oxfmt (oxc.oxc-vscode) as the formatter and source.fixAll.oxc on save, and installs the Oxc extension with cursor --install-extension when it creates the file.
Does Cursor use the VS Code Marketplace?
No. Cursor installs extensions from Open VSX, through its own proxy that scans them first. The Oxc, Biome, ESLint and Prettier extensions Ultracite uses are on Open VSX under the same IDs.
Why didn’t the Biome extension install in Cursor?
init installs it only when it creates .vscode/settings.json, and only if cursor is on your PATH (on macOS, run Shell Command: Install 'cursor' command). On a team plan, an allowed extensions list or install cooldown can block or delay it. Install it from the Extensions view instead.
Does Cursor read AGENTS.md?
Yes. Cursor applies AGENTS.md at the project root as plain-Markdown rules alongside .cursor/rules, and nested AGENTS.md files apply to their folder. It reads CLAUDE.md the same way.
Does the Cursor hook tell the agent what’s left to fix?
No. Cursor defines no output for afterFileEdit, so the hook fixes and formats the file and stops there. The agent finds what’s left through the linter errors it reads in the editor.
Why isn’t my Cursor hook running?
Project hooks only run in a trusted workspace. Workspace trust is off by default in Cursor, so this only matters if you’ve set security.workspace.trust.enabled; then trust the folder.

Ship less slop

One command sets up your linter, formatter, editor and agents. Works with Oxlint, Biome and ESLint.