agentsclimarketplace

Figma reliability patterns

Skill jeremylongshore/claude-code-plugins-plus-skills/skills/.curated/figma-reliability-patterns

425 plugins, 2,810 skills, 200 agents for Claude Code. Open-source marketplace at tonsofskills.com with the ccpi CLI package manager.

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill figma-reliability-patterns

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

'Build resilient Figma integrations with circuit breakers, fallbacks, and graceful degradation.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

8.3 KB, as published. Nobody here has run it

Figma Reliability Patterns

Overview

Production reliability patterns for Figma REST API integrations. Figma is an external dependency -- your application must handle its outages, rate limits, and slow responses without cascading failures.

Prerequisites

  • Working Figma API integration
  • Understanding of circuit breaker pattern
  • Cache or file system for fallback data

Instructions

Step 1: Circuit Breaker

// Prevent cascading failures when Figma is down
class FigmaCircuitBreaker {
  private failures = 0;
  private lastFailure = 0;
  private state: 'closed' | 'open' | 'half-open' = 'closed';

  constructor(
    private threshold = 5,        // Open after 5 failures
    private resetTimeMs = 30_000  // Try again after 30s
  ) {}

  async execute<T>(fn: () => Promise<T>): Promise<T> {
    if (this.state === 'open') {
      if (Date.now() - this.lastFailure > this.resetTimeMs) {
        this.state = 'half-open';
        console.log('[figma-circuit] State: half-open (testing recovery)');
      } else {
        throw new Error('Figma circuit breaker is OPEN -- failing fast');
      }
    }

    try {
      const result = await fn();
      if (this.state === 'half-open') {
        this.state = 'closed';
        this.failures = 0;
        console.log('[figma-circuit] State: closed (recovered)');
      }
      return result;
    } catch (error) {
      this.failures++;
      this.lastFailure = Date.now();

      if (this.failures >= this.threshold) {
        this.state = 'open';
        console.warn(`[figma-circuit] State: OPEN after ${this.failures} failures`);
      }
      throw error;
    }
  }

  getState() { return this.state; }
}

const figmaBreaker = new FigmaCircuitBreaker();

// Usage
async function safeFigmaCall<T>(fn: () => Promise<T>): Promise<T> {
  return figmaBreaker.execute(fn);
}

Step 2: Cached Fallback

import { readFileSync, writeFileSync, existsSync } from 'fs';

// Serve cached data when Figma is unavailable
class FigmaFallbackCache {
  constructor(private cacheDir = '.figma-cache') {}

  private getPath(key: string) {
    return `${this.cacheDir}/${key.replace(/[^a-zA-Z0-9]/g, '_')}.json`;
  }

  save(key: string, data: any) {
    const { mkdirSync } = require('fs');
    mkdirSync(this.cacheDir, { recursive: true });
    writeFileSync(this.getPath(key), JSON.stringify({
      data,
      cachedAt: new Date().toISOString(),
    }));
  }

  load(key: string): { data: any; cachedAt: string } | null {
    const path = this.getPath(key);
    if (!existsSync(path)) return null;
    return JSON.parse(readFileSync(path, 'utf-8'));
  }
}

const fallbackCache = new FigmaFallbackCache();

async function fetchWithFallback<T>(
  cacheKey: string,
  fetcher: () => Promise<T>
): Promise<{ data: T; fromCache: boolean; cachedAt?: string }> {
  try {
    const data = await safeFigmaCall(fetcher);
    // Update cache with fresh data
    fallbackCache.save(cacheKey, data);
    return { data, fromCache: false };
  } catch (error) {
    console.warn(`Figma unavailable, loading cached ${cacheKey}`);
    const cached = fallbackCache.load(cacheKey);
    if (cached) {
      return { data: cached.data as T, fromCache: true, cachedAt: cached.cachedAt };
    }
    throw new Error(`Figma unavailable and no cached data for ${cacheKey}`);
  }
}

Step 3: Retry with Backoff (Respecting Retry-After)

async function figmaRetry<T>(
  fn: () => Promise<Response>,
  maxRetries = 3
): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const res = await fn();

    if (res.ok) return res.json();

    if (res.status === 429) {
      const retryAfter = parseInt(res.headers.get('Retry-After') || '60');
      if (attempt < maxRetries) {
        console.warn(`429 -- waiting ${retryAfter}s (attempt ${attempt + 1}/${maxRetries})`);
        await new Promise(r => setTimeout(r, retryAfter * 1000));
        continue;
      }
    }

    if (res.status >= 500 && attempt < maxRetries) {
      const delay = Math.min(1000 * Math.pow(2, attempt), 30_000);
      const jitter = Math.random() * 1000;
      await new Promise(r => setTimeout(r, delay + jitter));
      continue;
    }

    throw new FigmaApiError(res.status, await res.text());
  }
  throw new Error('Max retries exceeded');
}

Step 4: Request Timeout

// Prevent requests from hanging indefinitely
async function figmaFetchWithTimeout(
  path: string,
  token: string,
  timeoutMs = 15_000
): Promise<Response> {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), timeoutMs);

  try {
    return await fetch(`https://api.figma.com${path}`, {
      headers: { 'X-Figma-Token': token },
      signal: controller.signal,
    });
  } catch (error) {
    if (error instanceof Error && error.name === 'AbortError') {
      throw new Error(`Figma request timed out after ${timeoutMs}ms: ${path}`);
    }
    throw error;
  } finally {
    clearTimeout(timeout);
  }
}

Step 5: Health-Aware Request Routing

// Only make non-critical Figma calls when the API is healthy
class FigmaHealthTracker {
  private healthy = true;
  private lastCheck = 0;
  private checkIntervalMs = 30_000;

  async isHealthy(token: string): Promise<boolean> {
    if (Date.now() - this.lastCheck < this.checkIntervalMs) {
      return this.healthy;
    }

    try {
      const res = await figmaFetchWithTimeout('/v1/me', token, 5000);
      this.healthy = res.ok;
    } catch {
      this.healthy = false;
    }
    this.lastCheck = Date.now();
    return this.healthy;
  }
}

const healthTracker = new FigmaHealthTracker();

async function conditionalFigmaCall<T>(
  token: string,
  critical: boolean,
  fn: () => Promise<T>,
  fallback: () => Promise<T>
): Promise<T> {
  const healthy = await healthTracker.isHealthy(token);

  if (!healthy && !critical) {
    console.log('Figma unhealthy, using fallback for non-critical call');
    return fallback();
  }

  return fetchWithFallback('default', fn).then(r => r.data);
}

Output

  • Circuit breaker preventing cascading failures
  • Cached fallback serving stale data during outages
  • Retry logic respecting Figma's Retry-After header
  • Request timeouts preventing hung connections
  • Health-aware routing for non-critical calls

Error Handling

IssueCauseSolution
Circuit stays openThreshold too lowIncrease threshold or decrease reset time
Stale fallback dataCache not refreshedRefresh cache on successful calls
Retry loopsNot respecting Retry-AfterAlways use the header value
Timeout too shortLarge file responsesIncrease timeout for /v1/files calls

Examples

Watch the circuit breaker (Step 1) do its job during a Figma incident:

12:04:11 figma request failed (503) — failure 1/5
12:04:13 figma request failed (503) — failure 5/5 → circuit OPEN for 30s
12:04:14 request short-circuited; serving cached tokens (age 8m) via fallback
12:04:44 circuit HALF-OPEN — probe /v1/me → 200 → circuit CLOSED

Confirm retry honors Retry-After instead of hammering (Step 3):

GET /v1/files/abc → 429 (Retry-After: 32)
sleeping 32s (server-directed, overrides backoff schedule)
GET /v1/files/abc → 200 (attempt 2)

The cached-fallback contract (what staleness is acceptable per consumer) is in references/cached-fallback.md; composition of all five patterns: references/health-aware-request-routing.md.

Resources

Next Steps

For policy enforcement, see figma-policy-guardrails.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.