Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/codex-apply-patch-hook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'onsystem': patch
---

The plugin's hook now checks edits in Codex. Codex installs the Claude Code plugin from the same marketplace and runs its hook on `apply_patch`, but the hook read only `tool_input.file_path`, and Codex puts the patch in `tool_input.command`, so every edit passed unchecked. The hook now reads the files a patch adds or updates from its `*** Add File:`, `*** Update File:` and `*** Move to:` lines, checks each `.tsx` or `.jsx` file in one run per project, and holds an updated file to the lines its hunks change, as it holds an Edit. It also reads the file from `path` or `filePath`, as other clients' tools name it, when the tool's input carries the text it wrote. Codex runs a plugin's hooks once you trust them in `/hooks`.

`init`, run in a terminal, offers to add a short section to the project's `AGENTS.md` (create-next-app writes one) or `CLAUDE.md`: use the onsystem tools before writing UI, and run `check_ui`, or `npx -y onsystem check <file>` without the tools, on every UI file changed. It sits between `BEGIN:onsystem-agent-rules` and `END:onsystem-agent-rules` comment markers, which a later run updates in place. A `CLAUDE.md` that imports `AGENTS.md` is left alone, and `--yes` never writes it.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ In a new create-next-app, the template page's hardcoded colors already make the
/plugin install onsystem@dgesteves
```

After each Write or Edit of a `.tsx` or `.jsx` file, the hook runs `onsystem check` on it. Errors go back to Claude as a blocking error with the fix, so Claude corrects the file before it moves on; warnings go as a note. It stays quiet in projects without a design system. [What it runs and touches](https://onsystem.vercel.app/docs/plugin).
After each Write or Edit of a `.tsx` or `.jsx` file, the hook runs `onsystem check` on it. Errors go back to Claude as a blocking error with the fix, so Claude corrects the file before it moves on; warnings go as a note. It stays quiet in projects without a design system. Codex installs the same plugin, and the hook checks the files its `apply_patch` changes. [What it runs and touches](https://onsystem.vercel.app/docs/plugin).

**Cursor or VS Code.** [![Install in Cursor](https://img.shields.io/badge/Cursor-Install_server-0d0f12?style=flat-square&logo=cursor&logoColor=white)](https://cursor.com/en/install-mcp?name=onsystem&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm9uc3lzdGVtIiwiLS1yb290IiwiJHt3b3Jrc3BhY2VGb2xkZXJ9Il19) [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_server-007ACC?style=flat-square)](https://insiders.vscode.dev/redirect/mcp/install?name=onsystem&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22onsystem%22%2C%22--root%22%2C%22%24%7BworkspaceFolder%7D%22%5D%7D), or commit the [config](https://onsystem.vercel.app/docs/clients#cursor-and-vs-code). The agent gets the tools and runs `check_ui` on what it writes.

Expand Down
8 changes: 4 additions & 4 deletions docs/clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@

The server speaks MCP over stdio, in both protocol eras: the 2026-07-28 revision (stateless, with `server/discover`) and the 2025 one (the `initialize` handshake), the era chosen by the client's first message. It finds the project from `--root`, a config file in the working directory, or the working directory itself when it holds a project (a `package.json` or `components.json`). MCP roots, which 2026-07-28 deprecates, are the fallback: when the working directory is none of those (Claude Desktop starts servers in `/`), a 2025-era client that reports roots has its first `file://` root used. When none of these gives a project (a client that starts servers in your home or the plugin's folder and reports no roots), each tool call's project is found from the absolute path it names, `path` (or `filename`, for `check_ui` with `code`): the nearest folder at or above it with a `package.json`, `components.json` or config, or the monorepo root above that, but never your home folder or the filesystem root. A project found this way loads a JSON config (`onsystem.config.json`) only: the server runs a JavaScript or TypeScript config only in a project it was started in. Until a call names one, the tools return an error that asks for it; after that, a call without one answers from the project found, as long as only one has been. Started at a [monorepo root](configuration.md#monorepo-roots), it serves every app and design-system package in it: the tools take the `path` of the file the agent is editing and answer for that file's project.

Every client gets the same five tools, including `check_ui`, which the agent runs on its own output. Only Claude Code has a hook that checks each edit as it happens, so there use the [plugin](plugin.md) instead; with other agents, add the [CI check](ci.md) so what the agent skips still gets caught.
Every client gets the same five tools, including `check_ui`, which the agent runs on its own output. Claude Code and Codex CLI also run the [plugin](plugin.md)'s hook, which checks each edit as it happens, so there use the plugin instead; with other agents, add the [CI check](ci.md) so what the agent skips still gets caught.

## Plugins for other agents

The skill and the MCP server also come packaged for other agents, pinned to the same release as the Claude Code plugin. Only the Claude Code plugin has the hook that checks each edit; elsewhere, the [CI check](ci.md) catches what the agent skips.
The skill and the MCP server also come packaged for other agents, pinned to the same release as the Claude Code plugin. Only the Claude Code plugin has the hook that checks each edit, and Codex runs it too; elsewhere, the [CI check](ci.md) catches what the agent skips.

- **Any agent with Agent Skills** (Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode and others): the skill, from the repository. It goes to `.agents/skills/onsystem`, which most agents read, and is linked into `.claude/skills` for Claude Code. Add the MCP server with your client's config below.

```sh
npx skills add dgesteves/onsystem
```

- **Codex CLI:** Codex reads the same marketplace as Claude Code and installs that plugin's server and skill. It also lists the plugin's hook, which is written for Claude Code's `Write` and `Edit` tools.
- **Codex CLI:** Codex reads the same marketplace as Claude Code and installs that plugin: the server, the skill and the hook, which checks each `.tsx` or `.jsx` file an `apply_patch` adds or updates. Codex runs a plugin's hooks only after you review and trust them: open `/hooks` once after installing.

```sh
codex plugin marketplace add dgesteves/onsystem
Expand Down Expand Up @@ -266,4 +266,4 @@ To share it with your team, add `--scope project`, which writes `.mcp.json` at t

Any other MCP client: run `npx -y onsystem --root /absolute/path/to/app` as a stdio server. On native Windows, wrap it as `cmd /c npx ...`.

The server sends usage instructions in its `initialize` result and in `server/discover`. Clients that ignore them benefit from one line in `CLAUDE.md`, `AGENTS.md` or `.cursor/rules`: _"Before writing UI, use the onsystem tools. Run check_ui on every file you change and fix all errors."_
The server sends usage instructions in its `initialize` result and in `server/discover`. Clients that ignore them benefit from one line in `CLAUDE.md`, `AGENTS.md` or `.cursor/rules`: _"Before writing UI, use the onsystem tools. Run check_ui on every file you change and fix all errors."_ Run in a terminal, `onsystem init` offers to add a short section that says so to the project's `AGENTS.md` or `CLAUDE.md`, with `npx -y onsystem check <file>` for agents without the tools. It sits between `BEGIN:onsystem-agent-rules` and `END:onsystem-agent-rules` comment markers, which a later run updates in place.
1 change: 1 addition & 0 deletions docs/plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The plugin is the fastest way to keep Claude on your design system. It bundles t
- **The design system's own files are left alone.** Like `check`, it skips them: an edit to `components/ui/button.tsx` changes the design system, which is a call for you and your reviewers rather than a lint error.
- **So is what `check .` leaves out.** A file the config's `exclude` covers, tests and stories by default (`*.test.tsx`, `*.stories.tsx`, `__tests__` folders) or a folder you list such as `app/legacy`, is not checked: the hook runs `check --skip-excluded`, which leaves such a file out even though it is named. Add a folder to `exclude` to keep the hook off code you don't hold to the design system. A project's own install from before that flag checks the file, as it did before.
- **It says when it can't check.** When the CLI can't run (npx can't fetch it because of a [min-release-age policy](troubleshooting.md#a-min-release-age-policy-blocks-npx), a private registry or no network, or the config is broken), it says so once per session and project, as a message to you, and never blocks the edit. When npm could not reach the registry, or npx didn't finish within the hook's 55 seconds, the hook doesn't start npx again for ten minutes, so an offline session waits for npm once, not on every edit.
- **Codex runs it too.** Codex installs this plugin from the same marketplace (`codex plugin add onsystem@dgesteves`) and runs the hook after each `apply_patch`, once you trust it in `/hooks`. It checks every `.tsx` or `.jsx` file the patch adds or updates, a moved file where it moved to, and holds an updated file to the lines its hunks change, as it holds an Edit. A patch's files are checked in one run per project.
- **Monorepos work.** The hook finds the project from the edited file, not from where Claude started, and the MCP server started at the root serves every project, answering for the file's own project when the tools get its `path`. When the monorepo root has a config or a baseline, as `init` there writes them, the hook runs the check from the root, as `check .` there does: the root config's rules apply to every project without a config of its own, and the root baseline covers every project. Since every project without a config of its own takes the root config on, the hook also checks a project without design-system components there, as `check .` at the root does (with neither components nor color tokens, only the accessibility rule runs in it). A project with a baseline of its own, as a CI job per app keeps, is checked from its own folder, and so is every project when the root is one project with a design system of its own (its config sets `components`, or it has a `components.json` or a `components/ui` folder), so each project's own components are still its design system.

## What it runs, and what it touches
Expand Down
Loading
Loading