This is the first entry in Arbor’s decision log — a running record of architecture choices that wanted more context than a commit message can hold. The decision log is mostly factual, mostly compact. This article reframes DL-001 as narrative because the story it tells is one of the most generalizable in Arbor’s first year: how toolchain drift compounds silently, and what to do about it.
If you’ve read this article and DL-001 the entry, you’ve seen the same content twice. The entry is the canonical reference. This is the version that orients the next operator who hits the same class of bug.
The symptom
The Figma Desktop Bridge — the connection that lets AI agents in Cursor and Claude create, update, and manage design tokens, variables, and components directly in Figma — had become unreliable. Work sessions were interrupted by connection drops, “Desktop Bridge not found” errors, and the bridge silently executing in the wrong file.
A session would start clean. A token edit would land. Then the next call would fail with a stale handle. Restarting Figma helped sometimes. Restarting Cursor helped sometimes. Nothing about the failure mode was deterministic, which is the worst shape of bug — fixable enough that nobody filed it, broken enough that nobody trusted the tool.
The story DL-001 tells isn’t “we fixed the bug.” It’s “we found four contributing causes, none of which were dramatic on their own.”
What was actually broken
An investigation uncovered four compounding problems:
-
Severely outdated MCP server. The local clone of
figma-console-mcpwas pinned at v1.5.0 while the upstream had reached v1.10.1 — 11 releases behind. Those releases included a fundamental transport change (CDP → WebSocket), stability fixes, port-discovery improvements, and multi-instance support. The 11-version gap had accumulated over a few weeks without anyone noticing. -
Two diverging clones. The project had been migrated from
~/.cursor/Arborto~/Documents/Arbor Design System, but the MCP config still pointed at the old location. Both clones existed at the same version, but documentation referenced one path while Cursor ran the other. Half the documented fixes worked. Half didn’t. -
No launch automation. Figma Desktop must be started with
--remote-debugging-port=9222for the CDP transport to work. There was no script or alias to enforce this. Every time Figma was restarted (update, crash, reboot) the debug port was lost and the bridge silently failed. The user had to remember the flag and apply it manually. They forgot, regularly. -
No update awareness. There was no mechanism to know when a new version of
figma-console-mcpwas available. The gap grew from v1.5.0 to v1.10.1 without surfacing. Toolchain drift was invisible.
None of the four causes was itself a crisis. Together they produced a tool that mostly worked and sometimes didn’t — the kind of unreliability that drains hours of attention before anyone admits the tool is broken.
What was done
Four fixes, each addressing one of the contributing causes:
- Updated to v1.10.1 and consolidated to a single clone in the workspace (
Arbor Design System/figma-console-mcp/). - Updated
~/.cursor/mcp.jsonto point to the workspace clone. One config, one truth. - Re-imported the Desktop Bridge plugin in Figma to pick up the new WebSocket-based transport and multi-port scanning.
- Created
scripts/launch-figma.sh— an idempotent script that launches Figma with the debug port, waits for readiness, and prints next-step instructions. Prevents the “forgot the flag” failure mode. - Created
scripts/check-figma-mcp-update.sh— a pre-session check that fetches from origin and reports if a newer version is available, with the exact commands to update.
The fix list is short. The principle behind it is longer, and that principle is what makes DL-001 useful to other parts of Arbor.
The principle: pin to a process, not a version
Most software-update conversations land on “we should upgrade more often” or “we should pin to a specific version.” Both miss the actual mechanism.
Upgrading more often is a discipline that decays. A team commits to “weekly upgrades” or “monthly upgrades” and is honoring it for the first three cycles. By the fourth, someone is shipping a deadline and skips the upgrade window. By the sixth, the upgrade ritual is dead and the toolchain is silently drifting again.
Pinning to a specific version is the opposite mistake. It’s stable, but it makes the drift invisible by design. The pin says “this is the right version” until somebody discovers, mid-incident, that it isn’t.
The third option is the one DL-001 picked: pin to a process that surfaces drift. The update-check script doesn’t auto-update. It doesn’t even notify a chat channel. It runs at the start of a session and prints the gap if one exists, along with the exact commands to close it. The cost of running it is two seconds. The cost of skipping it is the kind of compounding drift that DL-001 documents.
The process is load-bearing because:
- It runs at a moment when fixing the problem is cheap (session start, before any work depends on the tool).
- It surfaces the gap as text the operator can act on, not as a notification they can dismiss.
- It doesn’t require remembering — the script does the remembering.
After DL-001 shipped, this same pattern recurred in three other parts of Arbor:
- The CI drift guard for Code Connect files (DNG-142) — same shape, different toolchain.
- The app-icon regeneration check in the pre-commit hook + Buildkite step — pin to the process of regenerating, not the version of the generated artifact.
- The
figma:auditscript — pin to the process of checking Figma for drift against local tokens, not to a specific snapshot of either.
Each of these is “pin to a process” with a different concrete shape. DL-001 was the first time we recognized the pattern.
The other lessons
DL-001 records three additional lessons that compound with the main one:
-
Automate the launch ritual. A single flag (
--remote-debugging-port=9222) being forgotten can make an entire toolchain appear broken. Scripts remove the cognitive load. This is the operator equivalent of compile-time errors: the script encodes the precondition so the human doesn’t have to. -
One clone, one truth. Two copies of the same repo at different paths — even at the same version — creates confusion about which one is live. Consolidate early, before the confusion has a chance to mask other bugs.
-
WebSocket > CDP for plugin communication. The new transport is more resilient to Figma restarts and doesn’t require special launch flags for core operations. Upgrading was the single biggest stability win — even before the other three fixes landed, the transport change alone removed most of the visible failure modes.
That last lesson is worth pausing on. It’s the answer to “why did the upgrade matter, specifically?” — and the answer is that the upstream maintainers had already solved the bridge-stability problem we were experiencing. The 11-version gap meant we were running against a known-broken transport while the fix existed in main. The drift wasn’t just “we’re behind.” It was “we’re using software whose authors have already declared obsolete.”
What this means in Arbor
DL-001 is the first decision log entry for a reason. The class of bug it describes — silent toolchain drift on a dependency the team trusts — is the most likely class of bug in any AI-assisted design system, because the toolchain is large, the dependencies are fast-moving, and most of the friction is invisible until it isn’t.
The decision log itself was created in response to DL-001. Before DL-001, decisions like “we upgraded the MCP server” lived in commit messages and Slack threads. After DL-001, every architecture choice that wants more context than a commit message can hold gets an entry: context, decision, outcome, AI role, lessons.
Three years from now, the team probably won’t remember the specific Figma Console MCP version numbers. But the pattern — pin to a process, automate the launch ritual, one clone one truth — is what compounds across every later toolchain decision the project makes.
DL-001 isn’t important because the MCP server upgrade was important. It’s important because it’s the moment the team started writing down why.
Source: This article narrates DL-001 in the decision log. The log entry is the canonical reference; this is the orientation read.