diff --git a/.lintstagedrc.js b/.lintstagedrc.js index cf77f4f4c1..05b770767e 100644 --- a/.lintstagedrc.js +++ b/.lintstagedrc.js @@ -5,8 +5,7 @@ module.exports = { // Format HCL/Terragrunt files, but never touch generated *.lock.hcl (excluded via extglob) "!(*lock).hcl": (files) => { - // Prefer terragrunt's formatter for *.hcl; fall back to terraform fmt if needed - return files.map((f) => `terragrunt hclfmt --file "${f}"`); + return files.map((f) => `terragrunt hcl format --file "${f}"`); }, // Terraform files (format on commit) diff --git a/.tool-versions b/.tool-versions index 6b2685568f..d1b5c12b48 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,3 @@ nodejs 24.4.0 python 3.10.13 +terragrunt 1.0.4 diff --git a/ai/skills/plasmic-designer/README.md b/ai/skills/plasmic-designer/README.md new file mode 100644 index 0000000000..f48fd5f521 --- /dev/null +++ b/ai/skills/plasmic-designer/README.md @@ -0,0 +1,286 @@ +# Getting Started with Plasmic AI + +This guide walks you through everything you need to control your Plasmic project from an AI assistant (Claude Code, Claude Desktop, Codex, Cursor, etc.). Once set up, you can say things like _"add a hero section to the Homepage"_ and watch the AI read your project, design a section, and insert it into the canvas. + +The skill works by connecting your AI assistant to Chrome via the official [chrome-devtools-mcp](https://github.com/ChromeDevTools/chrome-devtools-mcp) MCP server. See the [Chrome DevTools MCP blog post](https://developer.chrome.com/blog/chrome-devtools-mcp-debug-your-browser-session) for background on what that is. + +**What you'll do in this guide:** + +1. Check prerequisites +2. Install the `chrome-devtools-mcp` server into your AI tool +3. Install the `plasmic-designer` skill into your AI tool +4. Run your first command end-to-end + +Each section ends with a **Verify** callout — a quick test you can run to confirm the step worked before moving on. + +--- + +## 1. Prerequisites + +Before you start, confirm you have the following: + +- **Node.js 20.19 LTS or newer.** Check with: + + ```sh + node --version + ``` + + If the version is older than `v20.19`, install the latest LTS from [nodejs.org](https://nodejs.org/) or via [nvm](https://github.com/nvm-sh/nvm). + +- **Google Chrome** (current stable, or Chrome for Testing). + +- **A Plasmic account** and a project open at [studio.plasmic.app](https://studio.plasmic.app). You'll need your **Project ID** — it's the string after `/projects/` in your Plasmic URL. For example, in `https://studio.plasmic.app/projects/j2Bm3mrbGNKsXVW3Wf5KpP` the project ID is `j2Bm3mrbGNKsXVW3Wf5KpP`. + +- **An AI assistant that supports MCP.** This guide covers: + - **CLIs**: Claude Code, Codex, Cursor, Opencode + - **GUI**: Claude Desktop + +--- + +## 2. Install `chrome-devtools-mcp` + +Pick **one** of the two tracks below, matching the tool you use. + +### 2A. For Agentic CLIs (Claude Code, Codex, Cursor, Opencode) + +If you're already comfortable with MCP configuration, this is a one-liner. + +**Claude Code**: + +```sh +claude mcp add chrome-devtools -- npx chrome-devtools-mcp@latest --no-usage-statistics +``` + +Alternatively, add the following to your project's `.claude/.mcp.json` or your user-global `~/.claude/.mcp.json`: + +```json +{ + "mcpServers": { + "chrome-devtools": { + "type": "stdio", + "command": "npx", + "args": ["chrome-devtools-mcp@latest", "--no-usage-statistics"] + } + } +} +``` + +**Cursor**: uses the same `mcpServers` JSON shape. Paste the snippet above into your Cursor MCP config (see [Cursor's MCP docs](https://cursor.com/docs/mcp)). + +**Codex**: uses TOML, not JSON. Add the following to `~/.codex/config.toml` (see [Codex MCP docs](https://developers.openai.com/codex/mcp)): + +```toml +[mcp_servers.chrome-devtools] +command = "npx" +args = ["chrome-devtools-mcp@latest", "--no-usage-statistics"] +``` + +**OpenCode**: uses a top-level `mcp` block in `opencode.json` (see [OpenCode MCP docs](https://opencode.ai/docs/mcp-servers/)): + +```json +{ + "mcp": { + "chrome-devtools": { + "type": "local", + "command": ["npx", "chrome-devtools-mcp@latest", "--no-usage-statistics"], + "enabled": true + } + } +} +``` + +> **Verify.** In your CLI, run `/mcp` (Claude Code) or ask _"list the MCP tools that are available"_. You should see tools beginning with `mcp__chrome-devtools__*` (e.g. `mcp__chrome-devtools__navigate_page`, `mcp__chrome-devtools__evaluate_script`). + +Skip ahead to [Section 3](#3-install-the-plasmic-designer-skill). + +### 2B. For Claude Desktop + +Claude Desktop requires a bit more care because it runs MCP servers as subprocesses that don't inherit your shell's `PATH`. Follow these steps in order. + +#### Step 1 — Locate the config file + +On macOS, the config lives at `~/Library/Application Support/Claude/claude_desktop_config.json`. The fastest way to open it: + +```sh +open -a TextEdit "$HOME/Library/Application Support/Claude/claude_desktop_config.json" +``` + +If the file doesn't exist yet, create it with an empty object `{}` inside. + +#### Step 2 — Find your absolute `npx` path + +Claude Desktop can't use a bare `"npx"` in the config — it needs the full path to the binary because MCP subprocesses don't inherit your shell's `PATH`. In Terminal: + +```sh +which npx +``` + +Example outputs, depending on how you installed Node: + +``` +/Users/you/.asdf/installs/nodejs/22.18.0/bin/npx +/Users/you/.nvm/versions/node/v22.11.0/bin/npx +/opt/homebrew/bin/npx +``` + +Keep that path handy — you'll paste it into the config in Step 3, and use the directory it's in for `env.PATH`. + +#### Step 3 — Add the MCP configuration + +Open `claude_desktop_config.json`. The file may be empty (`{}`) or it may already have content in it (such as a `"preferences"` block). Either way, you're going to **add a new top-level key called `"mcpServers"`** alongside whatever already exists — keep the existing content as-is. + +Before (your file might look like either of these — or something similar): + +**Empty file** + +```json +{} +``` + +**Existing config** + +```json +{ + "preferences": { + "quickEntryDictationShortcut": "capslock", + "sidebarMode": "chat" + } +} +``` + +You should add the `"mcpServers"` key as a sibling of any existing keys (using _your_ `npx` path from Step 2): + +```json +{ + "preferences": { + "quickEntryDictationShortcut": "capslock", + "sidebarMode": "chat" + }, + "mcpServers": { + "chrome-devtools": { + "command": "/Users/you/.asdf/installs/nodejs/22.18.0/bin/npx", + "args": ["chrome-devtools-mcp@latest", "--no-usage-statistics"], + "env": { + "PATH": "/Users/you/.asdf/installs/nodejs/22.18.0/bin:/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin" + } + } + } +} +``` + +What each part does: + +- `command` — absolute path to the `npx` binary. Required because Claude Desktop doesn't search your shell `$PATH`. +- `args[0]` — the package to run (`chrome-devtools-mcp@latest`). +- `--no-usage-statistics` — opts out of anonymous usage reporting. +- `env.PATH` — prepended with the node/npx directory, followed by typical system paths, so the MCP subprocess can find Chrome, git, and other system binaries it may need. Adjust the leading directory to match _your_ `npx` install path. + +Save the file. + +#### Step 4 — Fully restart Claude Desktop + +Quit Claude Desktop from the menu bar (**Claude → Quit Claude**). Closing the window isn't enough. Then open it again. + +> **Verify.** In Claude Desktop, open **Settings → Developer → Local MCP servers**. You should see a `chrome-devtools` entry with a blue **running** badge next to its name. The panel also shows the resolved `Command` and `Arguments` — confirm they match what you pasted. If the badge shows an error instead of **running**, click **View Logs** (or see the troubleshooting notes below). + +#### Claude Desktop troubleshooting + +| Symptom | Fix | +| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | +| `spawn npx ENOENT` | The `command` path is wrong. Re-run `which npx` and paste the exact output into `command`. | +| `Cannot find module 'chrome-devtools-mcp'` | Run `npx chrome-devtools-mcp@latest --help` in Terminal once to prime the npm cache, then restart Claude Desktop. | +| MCP server keeps dying | Check `~/Library/Logs/Claude/mcp*.log` (macOS). The log usually pinpoints the error. | +| Node version error | You're on Node < 20.19. Upgrade via [nvm](https://github.com/nvm-sh/nvm) or [brew](https://brew.sh). | + +If you're stuck, paste your config and the MCP log into Claude itself and ask for help — it can usually diagnose the issue. + +--- + +## 3. Install the Plasmic Designer Skill + +### 3A. For Agentic CLIs + +Skills live in a conventional directory your CLI already looks at: + +- **Claude Code** (per-project): `/.claude/skills/plasmic-designer/` +- **Claude Code** (user-global, available everywhere): `~/.claude/skills/plasmic-designer/` +- **Codex / Opencode / Cursor**: see each tool's skills documentation. + +Copy the skill folder: + +```sh +# User-global install (available from any project) +mkdir -p ~/.claude/skills +cp -r path/to/plasmic-designer ~/.claude/skills/ +``` + +The destination folder should contain: + +``` +plasmic-designer/ +├── SKILL.md +├── README.md +└── references/ + ├── design-guidelines.md + └── html-constraints.md +``` + +No other setup is needed — the CLI discovers skills automatically on start. + +> **Verify.** In your CLI, type `/plasmic-designer` (Claude Code) or ask _"what skills are available?"_. The `plasmic-designer` skill should appear in the list. + +### 3B. For Claude Desktop + +Claude Desktop supports custom skills via a ZIP upload. Your skill must be a ZIP file containing a folder with `SKILL.md` directly inside it. **The folder name must match the skill name** (`plasmic-designer`). + +1. Zip the `plasmic-designer` directory. From `ai/skills/` (the parent of `plasmic-designer/`), run: + + ```sh + zip -r plasmic-designer.zip plasmic-designer + ``` + +2. In the desktop app, go to **Customize → Skills**. +3. Click the **+** button, then choose **+ Create skill**. +4. Select **Upload a skill**. +5. Choose your `plasmic-designer.zip` file and upload it. +6. The skill appears in your list — toggle it on to activate it. + +> **Verify.** In Claude Desktop, start a new chat and ask _"what skills are available?"_. The `plasmic-designer` skill should appear in the list. + +--- + +## 4. First Use — End-to-End Walkthrough + +Let's design something. + +1. In your AI assistant, type: + + ``` + /plasmic-designer Add a hero section to the Homepage page + ``` + + Replace `` with your real project ID. In Claude Desktop, drop the `/plasmic-designer` prefix — start a new chat with the uploaded `plasmic-designer` skill toggled on and describe the task, including the project ID. + +2. The first tool call triggers an MCP permission prompt — _"Allow chrome-devtools to navigate_page?"_. Click **Allow**, and optionally **Always allow** so it doesn't ask again for this session. + +3. `chrome-devtools-mcp` launches a fresh Chrome window using its own dedicated profile. **The first time you run the skill, sign into Plasmic in that Chrome window** — the profile persists across runs, so you only need to do this once. + +4. Once you're signed in, ask the assistant to retry. It will navigate to your project, wait for the studio to load, read the component tree, and insert a new hero section. The Plasmic canvas updates live. + +5. Changes are normal Plasmic operations — hit **⌘Z** / **Ctrl+Z** inside Plasmic Studio to undo anything you don't like. + +--- + +## 5. Troubleshooting + +| Symptom | Likely cause | Fix | +| ----------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | +| `PLASMIC_AI_TOOLS is undefined` | Studio hasn't finished loading, or the page isn't a Plasmic project URL | Wait a few seconds and retry. Confirm the URL is `studio.plasmic.app/projects//`. | +| Assistant lands on the login page | Plasmic session expired or you haven't signed in yet in the MCP Chrome | Sign into Plasmic in the Chrome window that `chrome-devtools-mcp` opened, then ask the assistant to retry. | +| `spawn npx ENOENT` (Claude Desktop) | `PATH` is missing from the MCP subprocess | Use absolute paths for `command`, add `env.PATH` (see [Section 2B, Step 3](#step-3--paste-the-mcp-configuration)). | +| Node version error | Node < 20.19 | Upgrade Node. | +| Skill not listed in CLI | Wrong directory, or folder doesn't contain `SKILL.md` | Confirm `~/.claude/skills/plasmic-designer/SKILL.md` exists. | + +--- + +Feedback, bug reports, and feature requests: reach out in the [Plasmic community Slack](https://plasmic.app/slack) or on the [Plasmic forum](https://forum.plasmic.app/). diff --git a/ai/skills/plasmic-designer/SKILL.md b/ai/skills/plasmic-designer/SKILL.md new file mode 100644 index 0000000000..72fd80fed2 --- /dev/null +++ b/ai/skills/plasmic-designer/SKILL.md @@ -0,0 +1,207 @@ +--- +name: plasmic-designer +description: Build and modify Plasmic Studio designs using copilot tools via Chrome DevTools MCP. First argument should be a project ID, followed by the design request. Use this skill whenever the user mentions Plasmic, Plasmic Studio, visual web builder, or asks to design, build, edit, or modify UI components, pages, sections, or layouts inside a Plasmic project. Also trigger when the user references a Plasmic project ID, wants to add/remove/restyle elements in a visual editor, or asks about Plasmic component props, variants, slots, or tokens — even if they don't say "Plasmic" explicitly but describe visual design work that implies it. +allowed-tools: mcp__chrome-devtools__evaluate_script mcp__chrome-devtools__navigate_page mcp__chrome-devtools__take_screenshot mcp__chrome-devtools__list_pages +--- + +# Plasmic Designer + +Control Plasmic Studio through Chrome DevTools MCP to build and modify production-ready interfaces. + +## Arguments + +`$ARGUMENTS` should contain a **project ID** as the first word, followed by the design request. + +Example: `/plasmic-designer j2Bm3mrbGNKsXVW3Wf5KpP Add a hero section to the Homepage` + +If no project ID is provided, or if the conversation references multiple projects and it's unclear which one to use, ask the user to confirm the project ID before proceeding. + +## Setup + +The studio base URL is `https://studio.plasmic.app` by default. Only use `http://localhost:3003` if the user explicitly mentions localhost, a local dev server, or a local environment. + +1. **Navigate to the project** using `navigate_page` to open `{baseUrl}/projects/{projectId}/` + +2. **Wait for studio to load** — the studio takes a few seconds to initialize. Poll until the API is available: + ```javascript + async () => { + for (let i = 0; i < 15; i++) { + if (window.PLASMIC_AI_TOOLS) return { ready: true }; + await new Promise((r) => setTimeout(r, 2000)); + } + return { + ready: false, + error: "Studio did not load. Check the project ID and dev server.", + }; + }; + ``` + If `ready` is false, inform the user and stop. + +## Workflow + +Follow an explore-first pattern for every request: + +1. **Understand** — Use `read` to inspect the current state before making changes. If the request could reuse existing components (buttons, cards, navbars), read available components first and prefer reusing them over creating new HTML. +2. **Plan** — For complex requests, think through the sequence of operations before acting. Break large tasks into logical steps. +3. **Execute** — Make changes using the appropriate tools. +4. **Verify** — Use `take_screenshot` to visually confirm the result. Use `read` if you need to verify structural changes. + +## API Reference + +All tools are called via `evaluate_script` using async arrow functions (the tools return Promises). Each returns `{ success: true, output: "..." }` or `{ success: false, error: { message: "...", type: "..." } }`. + +Check `success` on every call. On failure, read the error message — common causes are invalid UUIDs or elements that don't exist. If a UUID-related error occurs, re-read the component to get fresh UUIDs before retrying. + +### read — Inspect project data + +```javascript +// Read all components and tokens +async () => { + return await window.PLASMIC_AI_TOOLS.read({ + project: { + components: true, + tokens: true, + screenBreakpoints: true, + globalVariants: true, + }, + }); +}; + +// Read a specific component +async () => { + return await window.PLASMIC_AI_TOOLS.read({ + components: [""], + }); +}; + +// Read specific elements within a component +async () => { + return await window.PLASMIC_AI_TOOLS.read({ + elements: [ + { componentUuid: "", elementUuid: "" }, + ], + }); +}; + +// Read specific tokens +async () => { + return await window.PLASMIC_AI_TOOLS.read({ tokens: [""] }); +}; +``` + +The output is often XML. Parse it to extract UUIDs, structure, props, variants, and slots. Large projects may return large results — read selectively by requesting specific components rather than everything. + +### insertHtml — Add HTML/CSS snippets + +```javascript +async () => { + return await window.PLASMIC_AI_TOOLS.insertHtml({ + html: "
...
", + componentUuid: "", + tplUuid: "", + insertRelLoc: "append", // "before" | "prepend" | "append" | "after" | "wrap" | "replace" + // variantUuids: [""] // optional, defaults to base variant + }); +}; +``` + +After insertion, the browser canvas updates automatically. + +### changeElement — Rename elements and/or modify CSS + +```javascript +async () => { + return await window.PLASMIC_AI_TOOLS.changeElement({ + componentUuid: "", + // variantUuids: [""], // optional + changes: [ + { + tplUuid: "", + // optional; pass null to remove the existing name + name: "HeroSection", + // optional; and null removes a property + styles: { + "background-color": "#1a1a2e", + padding: "48px 24px", + color: null, + }, + }, + ], + }); +}; +``` + +Each change entry can include a `name`, `styles`, or both. + +### deleteElement — Remove an element + +```javascript +async () => { + return await window.PLASMIC_AI_TOOLS.deleteElement({ + componentUuid: "", + tplUuid: "", + }); +}; +``` + +## Components & Variants + +### Targeting + +Mutation tools require a `componentUuid` (from `read` results). They accept an optional `variantUuids` array — when omitted, changes apply to the base variant. + +### Reusing Existing Components + +When you read a component, the output includes **props** (text, boolean, enum, number, href with defaults), **variants** (boolean toggles or enum option groups), **slots** (named content areas), **base-variant-tpl-tree** (element tree with styles), and **VariantSettings** (style overrides per variant). Review these to understand the component before using it. + +To use a component in insertHtml: + +```html + +
Slot content here
+
+``` + +- `data-plasmic-name` must exactly match the component name from `read()` (case-sensitive). +- `data-props` is a JSON object for both props and variant activations. Boolean variants: `"group": true`. Enum variants: `"group": "optionName"`. +- `slot="slotName"` on direct children fills a named slot. +- **Only layout/position styles work on instances**: width, height, min/max sizing, margin, position, top/left/bottom/right, z-index, order, align-self, flex-grow/shrink, opacity, display (only `none`), transform, and transition properties. Background, padding, color, font, border, etc. are ignored on instances — use `changeElement` on the component's root element instead. This is a Plasmic platform constraint, not a preference. + +## HTML Code Guidelines + +Before generating HTML, read `references/html-constraints.md` for the full set of rules. The key points: + +- Use ` +
+

Welcome

+

A place in the forest

+
+``` + +Reserve inline `style` attributes only for truly unique one-off values. + +## Responsive Design + +All designs must be responsive. Before generating HTML for a Page component, read the project's breakpoint configuration: + +```javascript +async () => { + return await window.PLASMIC_AI_TOOLS.read({ + project: { screenBreakpoints: true }, + }); +}; +``` + +Each breakpoint has a `name`, `uuid`, and `maxWidth`. Use `@media (max-width: px)` queries inside the `