# pi-figma

A [pi](https://github.com/mariozechner/pi-coding-agent) extension that lets the agent read Figma files without drowning in tokens.

---

## What the extension does

Raw Figma REST responses are enormous — a single design file can return **10–100 MB of JSON**, most of which is metadata the LLM will never use (vector paths, gradient stops, blend modes, render bounds). Dropping that directly into an agent's context is wasteful and often blows past the context window entirely.

`pi-figma` sits between pi and the Figma REST API and does three things:

1. **Transforms every response into a compact shape** before returning it. Hex colors instead of 0–1 RGB, integer bboxes, auto-layout essentials only, vectors stripped. On a real frame we measured **84.9% size reduction** vs the raw Figma response.
2. **Caches by Figma's native `version` field.** When the file hasn't been edited, repeat calls in the same session are local disk reads (~1 ms). When a designer edits, the `version` string changes and we refetch automatically.
3. **Ships a skill** (`skills/figma/`) that teaches the model cost-ordered tool selection — always use `figma_copy` before `figma_inspect`, always `figma_map` before fetching subtrees, never dump the whole file.

The extension exposes four tools the agent can call directly and one utility command (`/figma-cache-stats`).

### What this is *not*

- Not a Figma plugin (those run inside Figma itself).
- Not the Figma Dev Mode MCP server (that's a separate paid product that requires Figma Desktop open).
- Not a web scraper. Figma's canvas is WebGL, so CDP-based approaches don't see node data.

---

## Install

### From npm (recommended)

```bash
# global — available in every pi session
pi install npm:@originintelligence/pi-figma

# or project-local — only for this project
cd your-project
pi install -l npm:@originintelligence/pi-figma
```

### From git

```bash
pi install git:github.com/sanchezcodes/pi-figma
```

Pin a version with `@vX.Y.Z`. Git installs skip `pi update` when pinned.

### From a local checkout (for development)

If you've cloned the repo and want pi to load your working copy directly — useful for iterating on the extension itself:

```bash
pi install /absolute/path/to/pi-figma
# or project-local:
pi install -l /absolute/path/to/pi-figma
```

Pi reads local paths directly — no copying, no rebuild step. Any code change in `pi-figma/` is picked up the next time pi starts (or when you run `/reload` in an active session).

Verify it loaded:

```bash
pi
> /extension-status      # should list pi-figma
```

---

## Set up

The extension needs a Figma personal access token. Generate one at https://www.figma.com/developers/api#access-tokens — only the **File content** read scope is required for v1.

### Option A — env var (recommended)

Add to `~/.zshrc` (or `~/.bashrc`):

```bash
export FIGMA_PAT=figd_XXXXXXXXXXXXXXXXXXXX
```

Reload with `source ~/.zshrc` or open a new terminal. Launch pi normally.

### Option B — config file (fallback)

```bash
mkdir -p ~/.pi-figma
echo '{"pat":"figd_XXXXXXXXXXXXXXXXXXXX"}' > ~/.pi-figma/config.json
chmod 600 ~/.pi-figma/config.json
```

The extension checks `FIGMA_PAT` first, then falls back to this file. Useful if you can't modify shell rc files (shared hosts, locked-down macs).

### How to know it's working

In a pi session:

```
> map this Figma file https://www.figma.com/design/SOME_KEY/Name
```

Pi should call `figma_map` and return a list of pages/frames. If it errors with **"No Figma token found"**, the env var isn't visible to the pi process — usually because you exported in `.zshrc` but didn't restart the terminal.

---

## Capabilities

Four tools, ordered cheapest to most expensive. The skill in `skills/figma/` tells the model to prefer the cheaper one whenever possible.

| Tool             | What it returns                                                       | Typical payload |
|------------------|-----------------------------------------------------------------------|-----------------|
| `figma_copy`     | Flat list of UX text: `{ id, path, text }` per TEXT node             | smallest        |
| `figma_tokens`   | Registered design-system Styles (names only, no resolved values)      | small           |
| `figma_map`      | Page/frame tree: `{ id, name, type }` at configurable depth           | small           |
| `figma_inspect`  | Compact layout + visuals for one or more nodes (Dev-Mode-style)       | medium          |

### Accepted inputs

- **File**: a raw key (`abc123XYZ`) OR any Figma URL (`figma.com/file/...`, `figma.com/design/...`).
- **Node IDs**: `1:234` (API form), `1-234` (URL form), or a full URL with `?node-id=` — all parsed automatically.

### What every tool returns

- **Hex colors** (`#1a80e6`) or `rgba()` when alpha < 1 — never Figma's raw 0–1 RGB objects.
- **Integer bboxes** as `[x, y, w, h]`. No sub-pixel noise.
- **Auto-layout essentials only**: direction, padding, gap, radius. Skipped when at defaults.
- **`truncatedChildren: N`** counter when depth is capped — the agent knows what it didn't see.
- **No** vector path data, gradient stops, effect details, render bounds, export settings, blend modes (unless non-default).

### Utility command

```
/figma-cache-stats
```

Shows current disk usage of `~/.pi-figma/cache/`.

### Typical workflows the skill teaches

- **"Convert this frame to code"** → `figma_map` → find frame id → `figma_inspect(file, [id], depth=5)`.
- **"Audit copy for typos"** → `figma_copy(file)`.
- **"What design tokens exist?"** → `figma_tokens(file)`.
- **"Does this component match the DS?"** → `figma_tokens` for DS context → `figma_inspect` on the instance → compare.

---

## Architecture (brief)

```
pi-figma/
├── src/
│   ├── index.ts        # extension entry: registers tools + /figma-cache-stats
│   ├── client.ts       # REST fetch, auth resolution, URL/node-id parsing
│   ├── cache.ts        # gzipped disk cache, version-keyed, bounded at 2 versions/file
│   ├── transforms.ts   # raw Figma → compact (the token-saving layer)
│   ├── types.ts        # narrow types for what we actually consume
│   └── tools/
│       ├── map.ts
│       ├── inspect.ts
│       ├── copy.ts
│       └── tokens.ts
├── skills/figma/SKILL.md
└── scripts/smoke.ts    # end-to-end test script
```

**Rule of the house:** no code path returns a raw Figma response to the LLM. The `content` text in every tool is always the output of a `transforms.ts` function.

---

## Known limitations

- **`figma_tokens` misses Figma Variables.** v1 only reads the top-level `styles` map on `/v1/files/:key`. Modern files increasingly use **Variables** instead (separate endpoint at `/v1/files/:key/variables/local`). If `figma_tokens` returns zeroes on a file you know has colors, fall back to `figma_inspect` on a consuming node and read its `fill`. Fixing this is the #1 item on the v0.2 roadmap.
- **Personal access tokens are broad.** A Figma PAT has access to every file your account can see. Generate a separate PAT with minimal scope if this worries you.
- **Large sections still produce large output.** `figma_inspect` on a SECTION containing 12 full screens returns ~60 KB even after transform. The skill tells the agent to drill into a single frame when an inspect result is oversized, but it can still happen. If you see this, instruct the agent: "inspect just the first child, not the whole section."

---

## Roadmap

**v0.2** — ordered by proven need:
1. **Variables support in `figma_tokens`** — the big one, see limitation above.
2. `figma_export(file, nodeIds, format, scale)` — render frames to PNG/SVG/PDF. Named after Figma's "Export" button.
3. `figma_find(file, query)` — locate nodes by name pattern.
4. `figma_components(file)` — component/variant registry.
5. `detail: "full"` param on `figma_inspect` — opt-in unredacted fields (effects, gradient stops) for DS reverse-engineering.

**v0.3+** — stretch:
- Webhook ingestion for "notify on file change".
- Companion Figma plugin for inside-Figma selection → tool-call bridging.
- OAuth flow alternative to PAT, for shareable team setups.

---

## Testing

Typecheck:

```bash
cd /path/to/pi-figma
npm install
npm run typecheck
```

End-to-end smoke test against a live file (requires `FIGMA_PAT` in env):

```bash
npx -y tsx scripts/smoke.ts
```

The smoke script exercises all four tools against a real Figma file and reports payload sizes, fetch times, and cache-hit latencies. Use it as a regression harness after any change to `client.ts` or `transforms.ts`.

---

## License

MIT — see [LICENSE](./LICENSE).
