---
changelog:
  category: Release
  version: ultracite@8.0.0
date: '2026-10-11T00:51:03Z'
seo:
  description: >-
    Every agent now reads Ultracite's rules from AGENTS.md. init writes the
    rules there once, whichever agents you pick, and only adds a file for the
    four agents…
title: ultracite@8.0.0
type: changelog
---
## Major Changes

- d0875c0: Every agent now reads Ultracite's rules from `AGENTS.md`. `init` writes the rules there once, whichever agents you pick, and only adds a file for the four agents that need one more step to see them:
  
  - **Claude Code** reads `AGENTS.md` only when the project has no `CLAUDE.md`, so `init` adds an `@AGENTS.md` import to the project's `CLAUDE.md` or `.claude/CLAUDE.md` when there is one.
  - **Gemini CLI** reads `GEMINI.md` by default, so `init` adds `AGENTS.md` to `context.fileName` in `.gemini/settings.json`, keeping `GEMINI.md`.
  - **Aider** gets `.aider.conf.yml` pointed at `AGENTS.md`, as before.
  - **Replit Agent** reads only `replit.md`, so it keeps a copy of the rules there.
  
  Firebender now reads `AGENTS.md` too. The `init` prompt asks which agents you use and lists `AGENTS.md` (Universal) plus those four.
  
  Projects set up by earlier versions move over the next time `init` runs: it takes Ultracite's block out of `.claude/CLAUDE.md`, `GEMINI.md`, `.firebender/rules/ultracite.mdc` and Aider's `ultracite.md`, removes a file left with nothing else in it, and adds the import or settings that agent needs. That happens whenever one of those files still holds the rules, whichever agents you pick, since a leftover `.claude/CLAUDE.md` stops Claude Code from reading `AGENTS.md`.
  
  A `CLAUDE.md`, `GEMINI.md` or `replit.md` that is a symbolic link to `AGENTS.md`, or that `AGENTS.md` links to, already gives that agent the rules, so `init` leaves it as it is. `init` never writes through or removes a symbolic link to another file; it prints what to add to that file instead.
- 3ee5b8c: Aider now loads Ultracite's rules and lints each file it edits. Aider reads no instructions file on its own, so the `ultracite.md` that `init --agents aider` used to write was never loaded. Now `init` writes the rules to `AGENTS.md` and merges two keys into `.aider.conf.yml`: `read: AGENTS.md`, and `lint-cmd` set to the project's `ultracite fix`, which Aider runs on every file it edits, asking the model to fix whatever is left. The rest of the file, comments included, stays as written, a `lint-cmd` that runs another linter is left alone, and an `ultracite.md` that holds nothing but the rules is removed. Aider keeps its own option in the `init` prompt, since the universal `AGENTS.md` option doesn't write `.aider.conf.yml`.
  
  The agent list also uses the current names for Deep Agents, goose and Gemini CLI. Their `--agents` IDs don't change.
- f4c8a32: Make every rule in the Biome core preset an error. `noSuspiciousSemicolonInJsx` came from Biome's recommended set at warning level, so `ultracite check` passed with it unless the React preset was on. It and the two other rules core inherited from that set, `noDuplicateJsxProps` and `noVoidElementsWithChildren`, are now set to `error` explicitly.
- ed5ed04: `compat/compat` is now an error in the ESLint core preset. It was the last warning-level rule in any preset, so `ultracite check` passed while it reported browser APIs your [browserslist](https://github.com/browserslist/browserslist) targets don't support. Set your targets in a `browserslist` key in `package.json` or a `.browserslistrc` file, or turn the rule off in your config if the project only runs on a server.
  
  A project that sets no targets is now checked against [Baseline Widely available](https://web.dev/baseline) browsers (`baseline widely available`). eslint-plugin-compat used browserslist's `defaults` there, which include Opera Mini and Chrome 109, so `fetch`, `URL` and `Array#toSorted()` failed in almost every project. Ultracite only sets these targets when it finds no browserslist config from the directory ESLint runs in and no `BROWSERSLIST` environment variable, since the plugin would add them to your own targets rather than replace them. In a monorepo that sets targets only in its packages, add them at the root too, or set `settings.browsers` yourself.
- 16fa476: Lint the scripts in Vue, Svelte and Astro components with the ESLint core rules. Core's globs only matched `.js` and `.ts` files, so a `.vue` file got only the Vue rules, a `.svelte` file only the Svelte rules, and an `.astro` file's frontmatter only the Astro rules, while Oxlint already runs its core rules on those scripts. The `vue`, `svelte` and `astro` presets now apply core's rules to their components, including the TypeScript rules, with the type-checked ones off because a script block isn't part of a tsconfig.
  
  - Components now get core's filename rule like any other file, as on Oxlint, so a PascalCase component such as `TaskList.vue` is reported. SvelteKit route files (`+page.svelte`) are exempt, and Astro and Nuxt pages (`[slug].astro`, `[id].vue`) get the same route-aware pattern as other `pages/` files, on ESLint and in Oxlint's JS plugins.
  - In Svelte components and rune modules, `prefer-const`, `unicorn/no-top-level-assignment-in-function` and `sonarjs/declarations-in-global-scope` are off: `svelte/prefer-const` replaces the first, and the other two misread `$props()` and `$state` in a component's scope. SvelteKit's `PageProps` and `LayoutProps`, and Astro's `Props`, are allowed by `unicorn/name-replacements`.
- ed5ed04: Cypress and Storybook rules move out of the ESLint core preset into opt-in framework presets, `ultracite/eslint/cypress` and `ultracite/eslint/storybook`. Core loaded both plugins for every project, so `init` installed `eslint-plugin-cypress`, `eslint-plugin-storybook` and the whole `storybook` package for every ESLint setup, whether or not the project used them.
  
  `init` now offers `cypress` and `storybook` with the other frameworks (`--frameworks cypress storybook`). It preselects them when `cypress` or `storybook` is in `package.json`, and installs their plugins only when you pick them. To keep linting Cypress specs and stories, add the presets to `eslint.config.mjs` after `core`:
  
  ```js
  import core from "ultracite/eslint/core";
  import cypress from "ultracite/eslint/cypress";
  import storybook from "ultracite/eslint/storybook";
  
  export default [...core, ...cypress, ...storybook];
  ```
  
  Oxlint and Biome have no Cypress or Storybook rules, so `ultracite/oxlint/cypress`, `ultracite/oxlint/storybook`, `ultracite/biome/cypress` and `ultracite/biome/storybook` are empty presets that keep the framework selectable with every linter.
- ed5ed04: ESLint and Stylelint no longer run Prettier as a rule. `ultracite check` and `ultracite fix` already run Prettier as their own step, so the `prettier/prettier` rule from `eslint-plugin-prettier` and `stylelint-prettier` formatted and reported every file a second time. The ESLint core preset and the Stylelint preset drop those plugins and keep `eslint-config-prettier`, so no lint rule fights Prettier, and `init` no longer installs `eslint-plugin-prettier` or `stylelint-prettier`.
  
  ESLint and Stylelint now report only lint problems. Formatting problems come from the Prettier step of `ultracite check`, so running `eslint` or `stylelint` on their own no longer reports formatting. A config that sets `prettier/prettier` itself now fails with an unknown-rule error: remove that setting, or install the plugin and register it in your own config to keep it.
  
  Zed formats with Prettier on the ESLint toolchain. `init` used to set ESLint's language server as Zed's formatter for JavaScript, TypeScript and TSX, which only applied Prettier through the `prettier/prettier` rule, so in v8 Zed would have applied ESLint's fixes without formatting. It now keeps ESLint's fixes as code actions and sets `"formatter": "prettier"`, so Zed's Prettier integration formats afterwards with your project's Prettier config and plugins. Re-running `init` updates `.zed/settings.json`, and `ultracite upgrade --claude` or `--codex` makes the same change.
- ed5ed04: The ESLint rules that need type information are now opt-in, as they already are on Oxlint and Biome. The core preset no longer turns on the project service or the type-checked `@typescript-eslint` rules, such as `no-floating-promises`, `no-unsafe-return` and `strict-boolean-expressions`, so it lints TypeScript without a tsconfig and without building a TypeScript program, which is much faster. Where a type-checked rule replaced a core ESLint rule on TypeScript files (`no-implied-eval`, `no-throw-literal`, `prefer-destructuring`, `prefer-promise-reject-errors`, `require-await`), core now runs the ESLint rule, as Oxlint does without type information. The 37 SonarJS rules and one Unicorn rule that do nothing without type information, such as `sonarjs/deprecation`, `sonarjs/no-ignored-return` and `unicorn/no-non-function-verb-prefix`, move with them. SonarJS rules that use type information only when it's there, such as `sonarjs/no-small-switch` and its regular expression rules, stay in core.
  
  The type-checked rules live in a new `ultracite/eslint/type-aware` preset. Framework plugins with type-checked rules have an add-on after their preset: `ultracite/eslint/<framework>/type-aware` for `angular`, `jest`, `nestjs`, `qwik`, `tanstack` and `vitest`. `init --type-aware` adds the preset and the add-ons for the frameworks you pick, and re-running `init` without the flag keeps them. To keep type-aware linting, add them after `core` and after each framework:
  
  ```js
  import core from "ultracite/eslint/core";
  import typeAware from "ultracite/eslint/type-aware";
  import vitest from "ultracite/eslint/vitest";
  import vitestTypeAware from "ultracite/eslint/vitest/type-aware";
  
  export default [...core, ...typeAware, ...vitest, ...vitestTypeAware];
  ```
- 7965ec2: `ultracite fix --hook` now hands the problems it can't fix back to the agent. In Claude Code, CodeBuddy, Codex, Deep Agents, Grok Build and VS Code's Local agent (which runs the GitHub Copilot hook), the hook prints everything the linter and formatter report to stderr and exits with code 2 when problems remain, which those hosts show to the agent so it fixes them in its next step. Devin reads exit code 2 as "block", so under Devin the hook exits with 0 and passes the problems as `hookSpecificOutput.additionalContext` instead. Cursor and the Copilot CLI and cloud agent don't pass a hook's output to the agent, so their hooks keep the previous output and exit code.
- ed5ed04: `ultracite init` now asks before it changes files it doesn't own, and asks every question before it writes anything.
  
  - When you pick a linter other than the one the project uses, an interactive run lists the other linters' config files and packages and asks before removing them. If you keep them, init warns when `ultracite check` would still find and run the old linter. `--yes` removes them without asking, as before.
  - An ESLint setup keeps legacy `.eslintrc` files. ESLint 10 doesn't read them, so they can't conflict with the flat config, and `ultracite doctor` no longer flags them on an ESLint setup. Moving to Biome or Oxlint still removes them.
  - Init only turns on `strictNullChecks` in your `tsconfig*.json` files when type-aware linting is on, since only the type-aware rules need it, and an interactive run lists the files and asks first. It used to change every tsconfig on every run.
  - In a TypeScript project, an interactive run asks whether to turn on type-aware linting when `--type-aware` isn't passed. A project that already has it keeps it.
- ed5ed04: `ultracite init` has a `--yes` (`-y`) flag for running without prompts, and `--quiet` now only controls output.
  
  - `--yes` takes the default for every question no flag answers, without asking. Init does this on its own when `CI` is `true` or `1`, or when there's no terminal to answer prompts in, so it never waits for input in a pipeline.
  - `--quiet` leaves out the intro banner, spinners and progress messages, and no longer skips the prompts. A script that ran `init --quiet` to avoid them should pass `--yes --quiet`.
  - Warnings now print in quiet runs too, such as the one for a `check` or `fix` script that init left as it was because it runs another tool.
- cbb349c: Add three agents, and rename Windsurf to Devin Desktop.
  
  - `init --agents` now takes `fx` (Vercel Labs), `antigravity` (Antigravity CLI, Google's successor to Gemini CLI for consumer accounts) and `grok` (Grok Build). All three read `AGENTS.md`.
  - `init --hooks grok` writes a post-edit hook to `.grok/hooks/ultracite.json` in Claude Code's format. Grok Build runs it after each `Write` or `Edit` once you trust project hooks with `/hooks-trust`, and hands the problems `ultracite fix --hook` leaves back to the model. `fix --hook` now recognises Grok's own tool names (`search_replace`, `hashline_edit`), which it used to skip. Grok also reads `.claude/settings.json`, but runs a hook once when several files give it the same event, command and matcher, as the Claude Code and Grok Build hooks do, so a project can have both.
  - Windsurf is now Devin Desktop, with the editor and hook ID `devin` instead of `windsurf`, which init still accepts with a note to switch. Its hook now goes in `.devin/hooks.v1.json`, which Devin Local reads.
- ed5ed04: Ultracite now requires Node.js 22.18 or later, or Bun, and says so in its `engines` field. The CLI's dependencies have needed Node 22 since 7.10.0, so on Node 20 it stopped at startup with `TEXT_ENCODINGS.union is not a function`, and the `oxlint.config.ts` that `init` writes needs Node 22.18 to load on the Node 22 line. Node 20 reached end of life in April 2026.
  
  Requires Node.js >= 22.18.0
- ed5ed04: `ultracite init --type-aware` now turns on type-aware linting for Oxlint. It used to install `oxlint-tsgolint` without telling Oxlint to use it, so rules that need type information, such as `typescript/no-floating-promises`, only ran when you passed `--type-aware` to `ultracite check` yourself. Init now also sets `options: { typeAware: true }` in `oxlint.config.ts`, so `check`, `fix` and the editor extension run them. A config with an `options` object of its own is left as written, with a note to add `typeAware: true` to it. Re-running `init` on a project that has `oxlint-tsgolint` installed turns it on, which can report new problems.
- edc6ca6: Update the agents `ultracite init` sets up to match what's still shipping.
  
  - Remove Roo Code (shut down in May 2026), Continue (no longer maintained since Cursor acquired it), Firebase Studio (closing in March 2027) and MCPJam (an MCP testing tool rather than a coding agent). `--agents roo-code`, `continue`, `firebase-studio` and `mcpjam` now write the rules to `AGENTS.md`, as `universal` does, with a warning, and the skill installer no longer targets `.roo` or `.continue`. Files earlier versions wrote for them, such as `.roo/rules/ultracite.md`, are left in place.
  - Amazon Q CLI is now Kiro CLI, with the ID `kiro-cli` instead of `amazon-q-cli`, which init still accepts with a note to switch. Kiro reads `AGENTS.md` in both its CLI and IDE and ignores `.amazonq/rules` once a project has a `.kiro` folder, so init writes the rules to `AGENTS.md` (and `universal` covers it) instead of `.amazonq/rules/ultracite.md`.
  - Mux is now Xum, with the ID `xum` instead of `mux`, which init still accepts with a note to switch.
  - Kimi CLI is now Kimi Code CLI, with the ID `kimi-code` instead of `kimi-cli`, and Snowflake Cortex Code is now Snowflake CoCo, with the ID `snowflake-coco` instead of `snowflake-cortex`. The old IDs still work, with a note to switch. AMP is now Amp; its ID doesn't change.
- ed5ed04: The pre-commit hooks that `ultracite init` sets up now fix only the files you staged, instead of running `ultracite fix` on the whole project.
  
  - **Husky:** the hook passes the staged files to `ultracite fix` and re-stages them. A file you staged only part of is fixed but no longer re-staged, because `git add` would also have committed the changes you left unstaged. The hook lists those files so you can review the fixes and stage them yourself.
  - **Lefthook:** the job runs `ultracite fix {staged_files}`, so Lefthook passes the staged files that match its globs, and `stage_fixed` re-stages only those.
  - **pre-commit:** the hook no longer sets `pass_filenames: false`, so pre-commit passes the staged files to `ultracite fix`. It also sets `require_serial: true`, which keeps it to a single `ultracite fix` run.
  
  Since the globs now decide which files get fixed, the Lefthook job and the pre-commit hook match every file type the linters and formatters handle: `.js`, `.jsx`, `.mjs`, `.cjs`, `.ts`, `.tsx`, `.mts`, `.cts`, `.json`, `.jsonc`, `.css`, `.scss`, `.less`, `.vue`, `.svelte`, `.astro`, `.html`, `.md`, `.mdx`, `.yaml`, `.yml`, `.graphql` and `.gql`. Before, they matched only `.js`, `.jsx`, `.ts`, `.tsx`, `.json`, `.jsonc` and `.css`. The lint-staged glob, which already passed only the staged files that match it, now covers the same types too; it used to leave out `.mjs`, `.cjs`, `.mts`, `.cts`, `.less`, `.vue`, `.svelte`, `.astro`, `.html`, `.yaml`, `.yml`, `.graphql` and `.gql`, so those files were never fixed on commit. The pre-commit hook uses a `files` pattern instead of `types_or`, because pre-commit has no file type tags for `.jsonc`, `.mts`, `.cts` or `.gql`.
  
  Re-running `ultracite init` with the same integrations updates the hooks, globs and file types that earlier versions wrote, in place. Hooks, globs and types you wrote or edited yourself are left alone.
- ed5ed04: `ultracite init` and `upgrade` now install `oxlint`, `oxfmt` and `oxlint-tsgolint` within caret ranges of the versions the presets were checked against (`^1.86.0`, `^0.71.0` and `^7.0.2004`), instead of the latest release. Biome is still installed at the exact version. `oxfmt` is still before 1.0, so its caret range holds the minor version: a new `oxfmt` minor can no longer change how files are formatted the next time you run `upgrade`, and a new `oxlint` major can no longer fall outside the supported range. The `oxfmt` peer range is now `>=0.71.0 <1`, so `ultracite doctor` fails on an `oxfmt` older than 0.71.0 and warns on 1.0 or later.
  
  Requires oxfmt >= 0.71.0 and < 1.0.0
  
  Requires prettier >= 3.5.3 (the version `prettier-plugin-astro` needs)
- 528a17c: `ultracite upgrade` now brings your configuration up to date, not just your packages, and replaces the manual upgrade guides.
  
  - `--claude` and `--codex` hand the configuration changes a project still needs to that agent's CLI, after Ultracite and the toolchain are installed. The agent gets the upgrade guide for each major release the configuration predates: Biome 2's config format (v5), the per-framework presets (v6), the `ultracite/biome/*` preset paths and `check` and `fix` commands (v7), and this release's changes (v8): removing `prettier/prettier` from ESLint and Stylelint configs, importing the new Cypress, Storybook and type-aware ESLint presets where the project needs them, turning on Oxlint's `typeAware` when `oxlint-tsgolint` is installed, formatting with Prettier in Zed, and adding `--yes` to `init --quiet`. It runs as it does for `fix --claude`, limited to editing files, and Ultracite checks the project again afterwards, exiting non-zero when a change is still missing.
  - Which guides apply is decided from the project, not the version it came from, so a project that skipped a major release or had `ultracite` bumped by hand still gets them. Without an agent flag, `upgrade` lists them. They ship in the package under `skills/ultracite/references/upgrades/` and with the Ultracite skill.
  - `--version <version>` installs a given release, such as `7` (the newest 7.x) or `7.12.4`, instead of the latest. `--claude` and `--codex` need 8 or later, so `upgrade` stops before installing anything when they're passed with an earlier release.
  - When the package manager fails to install a package, `upgrade` and `init` print its output and how to retry instead of a stack trace, and for an npm peer dependency conflict (`ERESOLVE`) it suggests `legacy-peer-deps=true` in `.npmrc`.
  - Ultracite's own `-v` and `--version` now only work before a command, so `upgrade --version` is the upgrade's option. `ultracite --version` prints the version as before.

## Minor Changes

- 3883a3d: Add a post-edit hook for Codex. `init --hooks codex` writes `.codex/hooks.json` with a `PostToolUse` hook that runs `ultracite fix --hook` after each `apply_patch` edit, fixing just the files the patch adds, updates or moves. Codex loads the hook once you trust the project and review it in `/hooks`, and when the hook exits with code 2 it hands the problems `fix` couldn't settle to the model as the patch's result. See [Codex hooks](https://learn.chatgpt.com/docs/hooks).
- a30bde7: Add a post-edit hook for Deep Agents. `init --hooks deepagents` writes `.deepagents/hooks.json` in Claude Code's format, with a `PostToolUse` hook that runs `ultracite fix --hook` after each `Write` or `Edit`. Deep Agents Code (`dcode`) runs a project's hooks once you trust the workspace (headless runs need `--trust-project-hooks`), and when the hook exits with code 2 it appends the problems `fix` couldn't settle to the tool result the model reads.
- ed5ed04: `ultracite init --agents` no longer stops on an agent ID it doesn't know. Every agent reads the rules from `AGENTS.md`, so an unknown, retired or misspelled ID gets that file, as `universal` does, with a warning that lists the valid IDs. The old IDs of renamed agents and editors (`amazon-q-cli`, `mux`, `kimi-cli`, `snowflake-cortex` and `windsurf`) map to the new ones with a note to switch. `--editors` and `--hooks` still stop on an ID they don't know.

## Patch Changes

- ed5ed04: Agent hooks now run the project's installed Ultracite directly, as `npx ultracite fix --hook` (or `pnpm exec`, `bunx` and so on), instead of the project's `fix` script. Init leaves a `fix` script alone when the project already has one that runs another tool, and the hook then ran that tool with `--hook` added. Re-running `ultracite init --hooks` rewrites hooks from earlier versions in place.
- 3883a3d: `ultracite fix --hook` no longer fixes the whole project after an `apply_patch` edit that only deletes files. Such a patch leaves no file to fix, so the hook now does nothing, where it used to fall back to a whole-project run that could reformat files the agent never touched.
- 6bfeba2: Fix Biome refusing to run in a new project with no ignore file of its own. The core preset reads ignores from version control, and Biome looks for them only in the folder that holds `biome.jsonc`, so it stopped with "Biome couldn't find an ignore file" outside a git repository, and in a package below the repository root, until that folder had a `.gitignore`. When `init` creates `biome.jsonc` in a folder with no `.git`, `.gitignore` or `.ignore`, it now sets `vcs.root` to the repository root, or writes a `.gitignore` with `node_modules` when there's no repository.
- c9b606a: The Biome `core` preset now turns on [`noForIn`](https://biomejs.dev/linter/rules/no-for-in/) and [`noUndeclaredDependencies`](https://biomejs.dev/linter/rules/no-undeclared-dependencies/) as errors.
  
  `noForIn` reports every `for...in` loop, including guarded ones. Use `for...of` over `Object.keys()`, `Object.entries()` or an array instead. It had been off since it was a nursery rule, and stayed off when Biome 2.5 made it stable.
  
  `noUndeclaredDependencies` reports imports of packages that aren't declared in the closest `package.json`, which catches code that only works because a transitive dependency happens to be installed. It moves out of the `type-aware` preset: it's a Biome project rule, but `core` keeps the scanner out of `node_modules`, so turning it on made no measurable difference to `ultracite check` times. In a monorepo, a workspace package that imports a dependency declared only in the root `package.json` is now reported; declare the dependency in that package's own `package.json`. The ESLint preset already enforces this through `import-x/no-extraneous-dependencies` and `n/no-extraneous-import`.
- ed5ed04: The Biome `type-aware` preset no longer turns on `useImportExtensions`, which required a file extension on every relative import. The Oxlint and ESLint presets leave import extensions to the bundler and TypeScript (`import/extensions` is off), and Biome's `core` preset already had the rule off, so turning on type-aware linting no longer adds it.
- f43418c: `--hooks devin` works with Devin Local, Devin Desktop's only agent since 3.9.19. Earlier versions wrote a `post_write_code` hook to `.devin/hooks.json` for Cascade, which Devin Desktop removed, so the hook no longer ran. `init` now writes a `PostToolUse` hook to `.devin/hooks.v1.json`, in Claude Code's format, which Devin Local and [Devin CLI](https://docs.devin.ai/cli/extensibility/hooks/overview) read. Re-running `init` takes the old hook out of `.devin/hooks.json` and `.windsurf/hooks.json` and leaves your own hooks there, or removes a file left empty.
  
  Devin reads exit code 2 from a hook as "block", so when `ultracite fix --hook` runs under Devin (it sets `DEVIN_PROJECT_DIR`), it exits with 0 and prints what it couldn't fix as the hook's `hookSpecificOutput.additionalContext`, which Devin adds to the agent's context.
- ed5ed04: `ultracite init` now installs the linter's editor extension into the editor you picked. Every VS Code-based editor used to run `code --install-extension`, which put the extension in VS Code rather than in Cursor, Windsurf, Kiro or the others. Each editor now uses its own launcher: `code` for VS Code, `cursor` for Cursor, `devin-desktop` for Windsurf (now Devin Desktop, falling back to `windsurf` on installs from before the rename), `buddy` for CodeBuddy, `antigravity-ide` for Antigravity IDE, `bobide` for IBM Bob, `kiro` for Kiro, `trae` for Trae and `void` for Void. CodeBuddy's `codebuddy` command is its terminal agent, not the IDE, so init doesn't use it. When the launcher isn't on your `PATH`, init asks you to install the extension yourself, as it does when an install fails.
- f43418c: An editor extension install that takes longer than two minutes is now stopped and treated as failed, so a launcher that isn't the editor's own (such as `kiro` set to open Kiro CLI) can't hang `ultracite init`. Init then asks you to install the extension yourself, as it does for any failed install.
- ed5ed04: `init --frameworks angular` with ESLint now installs the `@angular-eslint/eslint-plugin` version the Angular preset is tested against, instead of the latest release, which could add or rename rules the preset didn't know about.
- ed5ed04: `ultracite check` and `fix` on the ESLint toolchain no longer warn about each file you pass that no ESLint config covers, such as `README.md` or `package.json`. A pre-commit hook that passes every staged file hit "File ignored because no matching configuration was supplied" on most commits. Ultracite now passes `--no-warn-ignored` to ESLint when you name files, unless you pass `--warn-ignored` or `--no-warn-ignored` yourself.
- f43418c: Antigravity IDE, CodeBuddy, Trae and Void now use the project's TypeScript version. They're built on VS Code releases before 1.111, which read `typescript.tsdk` and `typescript.enablePromptUseWorkspaceTsdk` rather than the `js/ts.tsdk.path` and `js/ts.tsdk.promptToUseWorkspaceVersion` settings `init` writes, so for those editors `init` writes both. Other editors keep only the new settings, since VS Code marks the old ones deprecated.
- e0bac18: `ultracite init --linter eslint` works with npm for React, Next.js, Astro and TanStack projects. `eslint-plugin-react`, `eslint-plugin-jsx-a11y` and `@tanstack/eslint-plugin-start` run on ESLint 10 but their `eslint` peer ranges stop at 9, so npm refused to install them next to it with `ERESOLVE unable to resolve dependency tree`. In npm projects, `init` and `upgrade` now add an [`overrides`](https://docs.npmjs.com/cli/configuring-npm/package-json#overrides) entry to `package.json` for each of those plugins that points its `eslint` peer at your own ESLint (`"eslint": "$eslint"`), so later `npm install` and `npm ci` runs work too. Overrides you already have for those packages are kept. pnpm, Yarn and Bun only warn about peer ranges, so their projects are left as they are.
- 6f5b7ba: Install the Ultracite skill where AdaL, IBM Bob and Qoder look for it. They read skills only from their own folders (`.adal/skills`, `.bob/skills`, `.qoder/skills`), never from the shared `.agents/skills`, so they never found it. `init` now installs the skill for each of them you choose in `--agents`, and for any whose folder the project already has.
- eb13a45: The `stylelint.config.mjs` that `ultracite init` writes on the ESLint toolchain now passes `ultracite check`. It was `export { default } from "ultracite/stylelint";`, which the ESLint core preset reports as a barrel file (`unicorn/no-barrel-files`), so a new project failed its first check on a file it never wrote. Init now writes `import config from "ultracite/stylelint";` followed by `export default { ...config };`, and re-running it replaces the old one-line config. A config you changed is left as it is.
- f43418c: `init --editors zed` with Oxlint now points you to the [Oxc extension](https://zed.dev/extensions/oxc), as it already did to Biome's, since Zed needs it to run Oxlint and Oxfmt. Zed's settings also stop asking for a `source.organizeImports.oxc` code action on save, which the Oxc extension doesn't provide; Oxfmt sorts imports when it formats.
- eb13a45: Zed's Oxlint settings no longer turn on type-aware linting by themselves. `init --editors zed` set `typeAware: true` for Oxlint's language server in every project, including ones without `oxlint-tsgolint` installed to run the type-aware rules. It now sets `typeAware: null`, so the language server follows `options.typeAware` in your Oxlint config, which `init --type-aware` sets. Re-running `init --editors zed` updates `.zed/settings.json`.
