|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +Figwright is an open-source, **bidirectional** Figma agent for MCP clients (Claude Code and others). It connects an MCP server to a Figma plugin over a local WebSocket relay, letting an AI agent both **read** designs with high-fidelity grounding and **write** back to the canvas — no Figma paid tier required. |
| 4 | + |
| 5 | +This file is the canonical guide for AI agents and contributors working in this repo. (`CLAUDE.md` points here.) |
| 6 | + |
| 7 | +## Architecture |
| 8 | + |
| 9 | +Two halves talk over a local WebSocket relay: |
| 10 | + |
| 11 | +- **MCP server** (`packages/mcp`, published as `@figwright/mcp`) — the Node process an MCP client launches. It exposes 80+ read/write tools, plus higher-level **grounding** tools that join Figma data with the user's codebase (component / token / icon maps) and a codegen prompt. It owns the relay, leader/follower **election** (multiple MCP servers can share one plugin), and request **idempotency**. |
| 12 | +- **Figma plugin** (`packages/plugin`) — a Vue 3 + Vite UI plus a sandbox that runs inside Figma and performs the actual Figma API calls. It connects out to the server's WebSocket. |
| 13 | +- **Shared** (`packages/shared`) — types, Zod schemas, the msgpack wire codec, and the plugin↔server protocol. It is **bundled into the server at build time** (not published on its own). |
| 14 | + |
| 15 | +Design stance: **provider-first**. Rather than a fixed compiler pipeline, the tools surface faithful, de-duplicated design context and let the LLM generate code that matches the user's actual stack (detected framework / styling system). The `figma-codegen` skill and the MCP `figma_to_code` prompt encode this approach. |
| 16 | + |
| 17 | +## Layout |
| 18 | + |
| 19 | +``` |
| 20 | +packages/ |
| 21 | + shared/ # types, Zod schemas, msgpack codec, plugin↔server protocol (bundled into mcp) |
| 22 | + mcp/ # the MCP server — @figwright/mcp (Node, ESM): relay, election, tools, joins |
| 23 | + plugin/ # Figma plugin — Vue 3 + Vite + Tailwind v4 (UI) + sandbox (Figma API) |
| 24 | + skills/ # Claude Code skills that orchestrate the tools (figma-codegen) |
| 25 | +test/ # cross-package integration tests (e.g. server tool registry ↔ plugin handlers) |
| 26 | +``` |
| 27 | + |
| 28 | +`packages/mcp/src` is organized by concern: `tools/`, `relay/`, `election/`, `join/` (component/token/icon maps), `tokens/`, `profile/` (stack detection), `scan/`, `icons/`, `prompts/`. |
| 29 | + |
| 30 | +## Tech stack |
| 31 | + |
| 32 | +- **Node 24** (see `.node-version`), **pnpm 10** workspace, ESM throughout. |
| 33 | +- **TypeScript** (strict). Build: **tsdown** (the server bundles `shared`); the plugin builds with **Vite** (single-file UI). |
| 34 | +- **Vitest** (tests), **oxlint** (lint), **oxfmt** (format), **knip** (unused deps/exports/files). |
| 35 | +- **Zod** for server tool I/O + shared schemas; **msgpack** on the wire. |
| 36 | + |
| 37 | +## Commands |
| 38 | + |
| 39 | +Run from the repo root: |
| 40 | + |
| 41 | +```bash |
| 42 | +pnpm install # install workspace deps |
| 43 | +pnpm typecheck # tsc across packages |
| 44 | +pnpm lint # oxlint |
| 45 | +pnpm format # oxfmt (write); `pnpm format:check` is the CI variant |
| 46 | +pnpm knip # unused deps / exports / files |
| 47 | +pnpm build # build all packages (tsdown + vite) |
| 48 | +pnpm test # vitest run — the canonical test command |
| 49 | +``` |
| 50 | + |
| 51 | +`pnpm test` from the root is **canonical** — it picks up both `packages/*/test/**` and the root `test/**`. Don't run tests per-package; you'll miss the cross-package suite. |
| 52 | + |
| 53 | +CI (`.github/workflows/ci.yml`) gates every push and PR on: **typecheck, lint, format:check, knip, build, test**. All must pass. |
| 54 | + |
| 55 | +## Conventions |
| 56 | + |
| 57 | +- **Commits / PRs**: [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `chore:`, `refactor:`, `ci:`, …). PR titles are validated by `semantic-pr.yml`; with squash merges the PR title becomes the commit on `main`. |
| 58 | +- **Tests**: each package has a `test/` mirroring `src/` (no co-located tests). Tests that span packages live in the root `test/`. |
| 59 | +- **Formatting & lint** run automatically on staged files via a lefthook pre-commit hook; typecheck + test run on pre-push. Don't hand-format. |
| 60 | +- **Scope**: internal packages are `@figwright/*`; only `@figwright/mcp` is published to npm. |
| 61 | + |
| 62 | +## Gotchas — read before changing `mcp` or `shared` |
| 63 | + |
| 64 | +- **The MCP server runs the BUILT `dist`, not source.** After changing anything in `packages/mcp` or `packages/shared`, run `pnpm build` and restart the MCP server — otherwise you're testing stale code. |
| 65 | +- **`@figwright/shared` is a devDependency and is bundled** into the server (tsdown `alwaysBundle`). Never move it to runtime `dependencies`, or `npm i @figwright/mcp` would try to fetch an unpublishable workspace package. |
| 66 | +- **Single-product versioning**: one version lives on `@figwright/mcp`. Root / shared / plugin are private and intentionally **not** version-synced — the git tag `vX.Y.Z` is the one product version. |
| 67 | + |
| 68 | +## Releasing |
| 69 | + |
| 70 | +Versioning and changelog are driven by Conventional Commits via **changelogen**: |
| 71 | + |
| 72 | +```bash |
| 73 | +pnpm release # bump @figwright/mcp, write the root CHANGELOG.md, commit + tag vX.Y.Z |
| 74 | +git push --follow-tags # the tag triggers .github/workflows/release.yml |
| 75 | +``` |
| 76 | + |
| 77 | +The release workflow builds and tests, publishes `@figwright/mcp` to npm (OIDC trusted publishing + provenance), creates the GitHub Release from the changelog, and attaches the Figma plugin as a downloadable zip (manifest + built `dist`) for manual import in Figma dev mode. |
0 commit comments