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
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

Bug reports with a minimal snippet and the `inspect` output are the most useful contribution: most fixes start from one. For a change in behaviour, open an issue first so we can agree on it before you write it.

## New integrations

Until Thursday 2026-11-19, four weeks after the public launch on 2026-10-22, we add no new integration (a client, a framework or another way to install or run onsystem) unless a user asks for it in an issue. That time goes to the integrations onsystem already has. To ask for one, [open an issue](https://github.com/dgesteves/onsystem/issues) that names it and says what you would use it for.

Fixes to the existing integrations are welcome at any time. So is checking a Tier 2 setup in the [support tiers](docs/clients.md#support-tiers): run it in the client, then open a pull request that moves its row to Tier 1 with the client's version, the date and what you saw (`test/support-tiers-docs.test.ts` lists the Tier 1 setups too).

## Setup

Node.js 22.18 or later (24 in `.nvmrc`) and pnpm, which Corepack provides at the version `package.json` names:
Expand Down
29 changes: 28 additions & 1 deletion docs/clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Pick your client below and add the server. Run it from the project, or pass `--root` with the app's absolute path: [how the server finds your project](#how-the-server-finds-your-project) has the rest.

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.
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. Not every setup below has been run in its client yet: [Support tiers](#support-tiers) says which have.

> [!TIP]
> **One `.mcp.json` for the team.** Commit this file at the repository root, and VS Code, GitHub Copilot CLI and Grok Build start the server from it once each person trusts the folder or approves the server:
Expand Down Expand Up @@ -300,6 +300,33 @@ Any other MCP client: run `npx -y onsystem --root /absolute/path/to/app` as a st

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.

## Support tiers

Every setup on this page follows the client's own docs, but not every one has been run in that client:

- **Tier 1, tested:** CI runs it on every pull request, or the setup as these docs give it was run in the client and worked.
- **Tier 2, documented:** written from the client's docs, and not run in the client yet, or only installed. It should work; if it does not, [open an issue](https://github.com/dgesteves/onsystem/issues) with the client's version.

| Setup | Tier | Last checked | What was checked |
| ------------------------------- | ---- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The MCP server over stdio | 1 | Every pull request | `pnpm smoke` starts the built server as a client does and calls every tool with the MCP SDK's clients, in both protocol eras. `pnpm pack-test` runs the handshake with the packed package on Linux, Windows and macOS. |
| Claude Code plugin | 1 | 2026-10-21, Claude Code 2.1.299 | `claude mcp list` showed the plugin's server connected ([#185](https://github.com/dgesteves/onsystem/pull/185)). CI runs the plugin's hook on every pull request, with input shaped like Claude Code's. |
| Claude Code without the plugin | 1 | 2026-10-21, Claude Code 2.1.299 | `claude mcp add --scope project` wrote the `.mcp.json` at the top of this page, and `claude mcp list` showed the server connected ([#185](https://github.com/dgesteves/onsystem/pull/185)). |
| Gemini CLI | 1 | 2026-10-16, Gemini CLI 0.64.0 | `gemini mcp add` wrote the config shown, and `gemini mcp list` showed the server connected in a trusted folder ([#185](https://github.com/dgesteves/onsystem/pull/185)). |
| Agent Skills (`npx skills add`) | 1 | 2026-10-10, skills 1.7.2 | It installed the skill in `.agents/skills/onsystem` and linked it into `.claude/skills` ([#73](https://github.com/dgesteves/onsystem/pull/73)). |
| Codex CLI | 2 | 2026-10-16, Codex CLI 0.163.0, install only | The plugin installed from the marketplace, and `codex mcp add` wrote the config shown ([#185](https://github.com/dgesteves/onsystem/pull/185)). Neither the server nor the hook has been run in Codex; CI tests the hook with input shaped like Codex's `apply_patch`. |
| GitHub Copilot CLI | 2 | 2026-10-16, Copilot CLI 1.0.98, install only | The plugin installed from the marketplace, and `copilot mcp list` listed its server and the one in a trusted folder's `.mcp.json` ([#185](https://github.com/dgesteves/onsystem/pull/185)). Neither was started. |
| Grok Build | 2 | 2026-10-09, Grok Build 1.0.50 | `grok mcp doctor` started the server and found its five tools, before the package was renamed onsystem ([#34](https://github.com/dgesteves/onsystem/pull/34)). |
| Cursor | 2 | Not yet | The plugin passes the checks of Cursor's plugin template ([#73](https://github.com/dgesteves/onsystem/pull/73)). Neither it nor `.cursor/mcp.json` has been run in Cursor. |
| VS Code | 2 | Not yet | From VS Code's docs. |
| Claude Desktop | 2 | Not yet | From Claude Desktop's docs. |
| Windsurf (Devin Desktop) | 2 | Not yet | From the Devin Desktop and Devin CLI docs. |
| JetBrains IDEs | 2 | Not yet | From the AI Assistant and Junie docs. |
| Zed | 2 | Not yet | From Zed's docs. |
| Antigravity | 2 | Not yet | From Antigravity's docs. |

The CLI, the [GitHub Action](ci.md) and the [ESLint plugin](eslint.md) are not agent setups: CI runs all three on every pull request. To move a setup to Tier 1, run it in the client and open a pull request that updates its row with the client's version, the date and what you saw.

## How the server finds your project

The server 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`). 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.
Expand Down
134 changes: 134 additions & 0 deletions test/support-tiers-docs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import fs from 'node:fs';
import path from 'node:path';

import { describe, expect, it } from 'vitest';

import { section } from './markdown.js';

// docs/clients.md gives every client a setup block of the same kind. Its "Support tiers" table
// says which setups have been run (Tier 1) and which follow the client's docs only (Tier 2), so an
// untested client does not read like a tested one. CONTRIBUTING.md holds new integrations back
// until four weeks after the public launch, and links the table.

const root = path.resolve(import.meta.dirname, '..');
const read = (file: string) =>
fs.readFileSync(path.join(root, file), 'utf8').replace(/\r\n/g, '\n');
const clients = read('docs/clients.md');
const contributing = read('CONTRIBUTING.md');

interface Row {
setup: string;
tier: string;
checked: string;
how: string;
}

/** The rows of the Support tiers table. */
function tiers(): Row[] {
const lines = section(clients, 'Support tiers')
.split('\n')
.filter((line) => line.startsWith('|'));
const [header, , ...body] = lines.map((line) =>
line
.slice(1, -1)
.split('|')
.map((cell) => cell.trim()),
);
expect(header).toEqual(['Setup', 'Tier', 'Last checked', 'What was checked']);
return body.map(([setup = '', tier = '', checked = '', how = '']) => ({
setup,
tier,
checked,
how,
}));
}

const PULL = /\[#\d+\]\(https:\/\/github\.com\/dgesteves\/onsystem\/pull\/\d+\)/;

describe('the support tiers in docs/clients.md', () => {
it('has a row for every client the page sets up', () => {
const setups = tiers().map((row) => row.setup);
// Each <details> block's client, without what its summary adds in brackets.
const summaries = [...clients.matchAll(/<summary><strong>(.+?)<\/strong><\/summary>/g)].map(
(m) => (m[1] ?? '').replace(/\s*\(.*\)$/, ''),
);
expect(summaries.length).toBeGreaterThanOrEqual(12);
// The plugin and the skill, which "Plugins for other agents" and plugin.md set up.
for (const name of [...summaries, 'Claude Code plugin', 'Agent Skills']) {
expect(
setups.some((setup) => setup.startsWith(name)),
name,
).toBe(true);
}
expect(new Set(setups).size).toBe(setups.length);
});

it('puts every row in Tier 1 or 2, and says when and how each was checked', () => {
for (const { setup, tier, checked, how } of tiers()) {
expect(['1', '2'], setup).toContain(tier);
expect(how, setup).not.toBe('');
if (checked === 'Every pull request') {
// CI runs it: the row names the command.
expect(tier, setup).toBe('1');
expect(how, setup).toMatch(/`pnpm [\w-]+`/);
} else if (checked === 'Not yet') {
expect(tier, setup).toBe('2');
} else {
// A check made once: its date, the client's version, and the pull request that shows it.
expect(checked, setup).toMatch(/^\d{4}-\d{2}-\d{2}, \S.* \d+\.\d+\.\d+/);
expect(how, setup).toMatch(PULL);
}
}
});

it('calls a setup tested only where CI or a pull request shows it', () => {
// A setup moves to Tier 1 with a pull request that ran it in the client and updates its row;
// add it here in the same change.
expect(
tiers()
.filter((row) => row.tier === '1')
.map((row) => row.setup),
).toEqual([
'The MCP server over stdio',
'Claude Code plugin',
'Claude Code without the plugin',
'Gemini CLI',
'Agent Skills (`npx skills add`)',
]);
// Nobody has run these: the launch audit could not check them, and no pull request has.
for (const setup of [
'VS Code',
'Cursor',
'Claude Desktop',
'Windsurf (Devin Desktop)',
'JetBrains IDEs',
'Zed',
'Antigravity',
]) {
expect(tiers().find((row) => row.setup === setup)?.checked, setup).toBe('Not yet');
}
});

it('is linked from the top of the page, before any setup', () => {
const intro = clients.slice(0, clients.indexOf('\n## '));
expect(intro).toContain('](#support-tiers)');
});
});

describe('the integration freeze in CONTRIBUTING.md', () => {
const freeze = () => section(contributing, 'New integrations');

it('holds new integrations for four weeks after the launch, unless an issue asks for one', () => {
// The launch was Thursday 2026-10-22: the freeze ends four weeks later, on the date it names.
expect(freeze()).toContain(
'Until Thursday 2026-11-19, four weeks after the public launch on 2026-10-22',
);
expect(freeze()).toContain('unless a user asks for it in an issue');
expect(freeze()).toContain('(https://github.com/dgesteves/onsystem/issues)');
});

it('links the support tiers', () => {
expect(freeze()).toContain('](docs/clients.md#support-tiers)');
expect(clients).toContain('\n## Support tiers\n');
});
});
Loading