Skip to content
Agentmart
Submit a tool

AGENTS.md · ChromeDevTools/chrome-devtools-mcp

AGENTS.md from ChromeDevTools/chrome-devtools-mcp: 213 lines covering Rules for TypeScript, Rules for Testing, Scope and PR description, Design and more.

Template by ChromeDevTools

IndexedApache-2.0★ 54,084
Write a review

Install

Works with Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code. Read the repository before you give any tool access to your data.

curl -fsSL https://raw.githubusercontent.com/ChromeDevTools/chrome-devtools-mcp/main/AGENTS.md -o AGENTS.md

Read it and adapt it to your project before use.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

The AGENTS.md file that ChromeDevTools/chrome-devtools-mcp (54,083 stars) keeps for coding agents. It has 213 lines in 7 sections: Rules for TypeScript; Rules for Testing; Scope and PR description; Design; Correctness and edge cases; Tests; Documentation and output. Use it as a model for your own project's instructions.

Use cases: prompt-engineering

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

What's in it

An AGENTS.md file: instructions coding agents (Codex, Cursor, Copilot, Gemini CLI and others) read before working in a repo.

For
Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code
Length
213 lines
File
AGENTS.md

Sections

  1. Rules for TypeScript
  2. Rules for Testing
  3. Scope and PR description
  4. Design
  5. Correctness and edge cases
  6. Tests
  7. Documentation and output

First lines (shown under the repo's Apache-2.0 license)

This repository contains an MCP server and CLI for Chrome DevTools.

# Instructions

- Use only scripts from `package.json` to run commands.
- Use `npm run build` to run tsc and test build.
- Use `npm run test` to build and run tests, run all tests to verify correctness.
- Use `npm run test path-to-test.ts` to build and run a single test file, for example, `npm run test tests/McpContext.test.ts`.
- Use `npm run format` to fix formatting and get linting errors.
- Never modify `third_party/devtools-frontend` except for experimentation: it is a git submodule, a mirror of the actual codebase.

## Rules for TypeScript

- Do not use `any` type.
- Do not use `as` keyword for type casting.
- Do not use `!` operator for type assertion.
- Do not use `// @ts-ignore` comments.
- Do not use `// @ts-nocheck` comments.
- Do not use `// @ts-expect-error` comments.
- Prefer `for..of` instead of `forEach`.
- Never type-check types that are already type safe (e.g. redundant `typeof` checks on statically typed variables).

## Rules for Testing

### Structure and Separation of Concerns

- **Prefer mock-based unit tests over real-browser tests**: Do not use `withMcpContext` or launch a real browser unless the test genuinely requires real browser or DevTools protocol integration (e.g., live CDP events, browser lifecycle, secondary sessions). Puppeteer already tests browser behavior upstream; unit tests run faster and avoid browser overhead.
- **Tool handler tests (`tests/tools/*.test.ts`)**:
  - Test that the tool handler parses/validates parameters and invokes the corresponding methods on `page`, `context`, or `response` with the exact expected arguments.
  - Do **not** reimplement business logic or state tracking inside mocks (e.g., do not simulate state changes in mock methods).
- **Core class tests (e.g., `tests/McpPage.test.ts`)**:
  - Test business logic by instantiating the real class under test with mocked dependencies (e.g., instantiate `new McpPage(...)` with a mocked Puppeteer page from `createMockPuppeteerPage()`).
  - Assert that the class calls the underlying Puppeteer methods with the expected parameters.

### Mocking Guidelines (`tests/mocks.ts`)

- **Centralize mocks in `tests/mocks.ts`**: Keep all reusable mock factories in `tests/mocks.ts`. Import directly from `tests/mocks.ts` (do not re-export from `tests/utils.ts`).
- **Use `sinon.createStubInstance(Class)`**: Do not hand-roll mock objects or define custom mock interfaces. Use `sinon.createStubInstance()` so all prototype methods are automatically stubbed.
- **Typing**: Use `sinon.SinonStubbedInstance<Class>` for mock types (e.g., `MockMcpPage`, `MockMcpContext`, `MockMcpResponse`).
- **Handler mocks helper**: For tool handlers, use `const {page, context, response} = createHandlerMocks();` from `tests/mocks.ts` to set up all three mocks in one call.
- **Keep mocks generic**: Do not tailor mocks to a specific tool or test suite.
- **Naming conventions**: Use `mock` rather than `fake` in helper and variable names (e.g., `createMockPuppeteerPage`, `createMockMcpPage`). Name the mocked Puppeteer page instance `pptrPage`.

### Assertions and Sinon Best Practices

- **Use `sinon.assert` methods**: Do not use Node's `assert.ok(stub.calledOnce)` or `assert.deepStrictEqual(stub.firstCall.args[0], ...)` to verify stub calls.
- **Verify exact arguments**:
  - Use `sinon.assert.calledOnceWithExactly(stub, ...args)` for single calls with exact arguments.
  - Use `sinon.assert.calledWithExactly(stub.secondCall, ...args)` for subsequent calls.
  - Use `sinon.assert.notCalled(stub)` to assert a method was not invoked.
- **Clean up stubs**: `tests/setup.ts` runs `sinon.restore()` after every test. Do not add `afterEach(() => sinon.restore());` to test suites.

### Test Cleanliness

- Do not add redundant comments or verbose JSDoc for short, self-describing mock functions or tests.
- Only test real scenarios; avoid testing redundant or artificial calls that cannot happen in real usage.
- Use current year (2026) in copyright headers for new test files.

# Pre-submit checklist

Complete every item before you upload a PR or push a new revision.

## Scope and PR description

- [ ] The PR contains one change. Move unrelated refactors, renames,
      formatting changes, and build or compiler changes into their own PR.
- [ ] The PR title, the commit type (`fix:`, `feat:`, `chore:`), and the
      squash commit message describe the same change. A change to a default
      value or to tool output is a `fix:` or a `feat:`, not a `chore:`.
- [ ] The PR description lists every user-visible behavior change, including
      changes to other tools that share the changed code path.
- [ ] The PR description matches the shipped behavior. Remove claims about
      fixes that the diff does not contain.
- [ ] The PR description names new functions that have no production caller
      yet, or the PR removes them.
- [ ] The branch has no merge conflicts with `main`. Rebase only when a
      conflict exists.
- [ ] `npm run gen` ran after a change to a tool schema, a tool description,
      or a CLI option. The generated files are committed.
- [ ] `npm run format` ran. No line is longer than 80 columns.
- [ ] `npm run test` passed locally. CI failures on all platforms are your
      responsibility.

## Design

- [ ] The change lives in the lowest layer that owns the data: page logic in
      `McpPage`, context logic in `McpContext`, formatting in
      `src/formatters/*`. `McpResponse` does not resolve pages or workers.
- [ ] If Puppeteer or devtools-frontend owns the bug, fix it there first. Do
      not copy or re-implement upstream code in this repository.
- [ ] Puppeteer internals are imported only through `src/third_party/index.ts`.
- [ ] Repeated code is one helper. Extract a helper when the same block
      appears two or more times. Prefer an existing helper or a Puppeteer
      utility (for example `Deferred`) over a new one.
- [ ] A new formatter class exposes `toJSON()` and `toString()`, and
      `toString()` uses the `toJSON()` output.
- [ ] A function with three or more optional parameters takes one options
      object. Do not pass positional `undefined` placeholders.
- [ ] Each default value is declared in one place.
- [ ] A new behavior is opt-in by default when a wrong classification fails
      silently (for example a config option is restart-required unless the
      author marks it reloadable).
- [ ] An invalid combination of flags or options is rejected by the type
      system where possible, not only by a comment.
- [ ] No public method exists only to serve a test. Put shared helpers in
      `src/utils/*`.
- [ ] Parameter validation lives in the Zod schema (`refine`, `coerce`), not
      in the handler. Validation runs before the handler changes any state.
- [ ] Numeric validation matches what the consumer accepts. Use
      `Number.isInteger` and a range check where CDP expects integers.

## Correctness and edge cases

- [ ] A failed external call does not leave stale state. Restore the previous
      value when a call rejects.
- [ ] An error path still produces the artifacts and partial results the
      agent needs before it throws.
- [ ] An async operation that a timeout can abandon checks that its target
      (browser, page, config) is still current when it resumes.
- [ ] A lock or guard is acquired and released exactly once. A helper that
      releases a guard throws when the guard is already released.
- [ ] Concurrent callbacks (watchers, reloads, event handlers) are
      serialized. A transient failure does not trigger a callback.
- [ ] A filesystem operation that races with another process tolerates the
      race (`fs.rmSync(path, {force: true})` or `try/catch`), not
      `existsSync` + an unguarded call.
- [ ] A failed lookup falls back to the previous behavior. It does not turn
      a healthy state into an error state.
- [ ] No synchronous process spawn or blocking call runs in a polling loop
      or in a hot function.
- [ ] `dispose()` releases every resource the object created, and runs for
      objects that are already closed.
- [ ] Event listeners added for one action are removed when the action ends.
- [ ] Cached page-side state is refreshed before use. The page can reload
      between tool calls.
- [ ] Behavior shared by all tools that act on the selected page also runs
      for tools defined with `defineTool`, not only `definePageTool`.
- [ ] String and URL parsing handles userinfo, escaped delimiters, ports,
      pattern groups, and empty or whitespace-only input. Use the full
      authority, not a heuristic on the first or last character.
- [ ] Truncation uses `Intl.Segmenter` graphemes, not `string.slice`.
- [ ] Secrets never reach logs. Redact headers, URL userinfo, and query
      strings in every log line, including process startup arguments.
- [ ] A filesystem path parameter is validated with `validatePath()` even
      when the value parses as a URL. The error says what the parameter
      expects.
- [ ] A value that crosses a process boundary (daemon IPC, CLI) is
      serialized with `JSON.stringify` when it is not a primitive.
- [ ] An identifier is issued only for items that a tool can resolve later.
- [ ] A dedup key never collapses for items without identifying fields.
      Use a counter or skip such items.
- [ ] An error message names the exact condition that failed, with the
      relevant values (pid, timeout, URL, parameter name).
- [ ] A thrown non-`Error` value keeps its content in the error message.
      Treat objects with a string `message` like `Error`.
- [ ] Optional chaining and `?? default` are not applied to values whose
      type is non-optional.
- [ ] Version-dependent behavior (Node, Chrome, OS) is tested on every
      version the `engines` field allows, or the test does not depend on it.

Signals

Stars
54,084
Forks
6,417
Open issues
78
Contributors
156
Last commit (this folder)
Oct 19, 2026 (10 days ago)
Last release
Oct 22, 2026 (7 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
Apache-2.0
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from ChromeDevTools

Cite this page

AGENTS.md · ChromeDevTools/chrome-devtools-mcp. Agent Mart. https://agentmart.dev/templates/chromedevtools-chrome-devtools-mcp-agents-md (last updated 2026-10-24)