Claude-code-plugins-plus gamma-performance-tuning
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/gamma-pack/skills/gamma-performance-tuning" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-gamma-performance-tuning && rm -rf "$T"
manifest:
plugins/saas-packs/gamma-pack/skills/gamma-performance-tuning/SKILL.mdsource content
Gamma Performance Tuning
Overview
Optimize Gamma API integration performance. Gamma's generate-poll-retrieve pattern means most latency is in generation time (10-60s), not API call overhead. Optimize by: reducing poll overhead, parallelizing batch operations, caching results, and choosing the right generation parameters.
Prerequisites
- Working Gamma integration (see
)gamma-sdk-patterns - Understanding of async patterns
- Redis or in-memory cache (recommended)
Performance Characteristics
| Operation | Typical Latency | Notes |
|---|---|---|
POST | 200-500ms | Just starts the generation |
GET (poll) | 100-300ms | Per poll request |
| Full generation (poll to completion) | 10-60s | Depends on content + cards |
GET | 100-200ms | Cacheable |
GET | 100-200ms | Cacheable |
Instructions
Step 1: Optimize Poll Strategy
// src/gamma/smart-poll.ts // Adaptive polling: start fast, slow down over time export async function smartPoll( gamma: GammaClient, generationId: string, opts = { maxTimeMs: 180000 } ): Promise<GenerateResult> { const deadline = Date.now() + opts.maxTimeMs; let interval = 2000; // Start at 2s while (Date.now() < deadline) { const result = await gamma.poll(generationId); if (result.status === "completed") return result; if (result.status === "failed") throw new Error("Generation failed"); // Adaptive backoff: poll faster early, slower later await new Promise((r) => setTimeout(r, interval)); interval = Math.min(interval * 1.5, 10000); // Max 10s between polls } throw new Error(`Poll timeout after ${opts.maxTimeMs}ms`); }
Step 2: Cache Static Data
// src/gamma/cache.ts import NodeCache from "node-cache"; const cache = new NodeCache({ stdTTL: 3600 }); // 1 hour for static data export async function getCachedThemes(gamma: GammaClient) { const key = "gamma:themes"; const cached = cache.get(key); if (cached) return cached; const themes = await gamma.listThemes(); cache.set(key, themes); return themes; } export async function getCachedFolders(gamma: GammaClient) { const key = "gamma:folders"; const cached = cache.get(key); if (cached) return cached; const folders = await gamma.listFolders(); cache.set(key, folders); return folders; } // Cache generation results (useful for showing status) export async function cacheGenerationResult( generationId: string, result: GenerateResult ) { cache.set(`gamma:gen:${generationId}`, result, 86400); // 24 hours }
Step 3: Parallel Batch Generation
// src/gamma/batch.ts import pLimit from "p-limit"; const limit = pLimit(3); // Max 3 concurrent generations export async function batchGenerate( gamma: GammaClient, requests: Array<{ content: string; exportAs?: string }> ): Promise<Array<{ index: number; result?: GenerateResult; error?: string }>> { const results = await Promise.allSettled( requests.map((req, index) => limit(async () => { const { generationId } = await gamma.generate({ content: req.content, outputFormat: "presentation", exportAs: req.exportAs, }); const result = await smartPoll(gamma, generationId); return { index, result }; }) ) ); return results.map((r, i) => { if (r.status === "fulfilled") return r.value; return { index: i, error: (r.reason as Error).message }; }); }
Step 4: Reduce Generation Time
// Shorter content = faster generation // "brief" text = fewer AI-generated words per card = faster // SLOWER: extensive text on many cards await gamma.generate({ content: "Comprehensive 20-card guide to machine learning...", outputFormat: "presentation", textAmount: "extensive", // More text per card = slower }); // FASTER: brief text, fewer implied cards await gamma.generate({ content: "5-card overview of ML basics: supervised, unsupervised, reinforcement, deep learning, applications", outputFormat: "presentation", textAmount: "brief", // Less text per card = faster }); // FASTEST: preserve mode (no AI text generation) await gamma.generate({ content: "Your pre-written slide content here...", outputFormat: "presentation", textMode: "preserve", // Uses your text as-is, no AI rewriting });
Step 5: Preload Data at Startup
// src/gamma/preload.ts // Fetch themes and folders at app startup, not per-request let preloaded = false; export async function preloadGammaData(gamma: GammaClient) { if (preloaded) return; const [themes, folders] = await Promise.all([ gamma.listThemes(), gamma.listFolders(), ]); // Cache for the session cache.set("gamma:themes", themes, 0); // No TTL (until restart) cache.set("gamma:folders", folders, 0); preloaded = true; console.log(`Preloaded ${themes.length} themes, ${folders.length} folders`); }
Step 6: Connection Keep-Alive
// src/gamma/optimized-client.ts import http from "node:http"; import https from "node:https"; // Reuse TCP connections const agent = new https.Agent({ keepAlive: true, maxSockets: 10, keepAliveMsecs: 60000, }); export function createOptimizedClient(apiKey: string) { const base = "https://public-api.gamma.app/v1.0"; const headers = { "X-API-KEY": apiKey, "Content-Type": "application/json" }; async function request(method: string, path: string, body?: unknown) { const res = await fetch(`${base}${path}`, { method, headers, body: body ? JSON.stringify(body) : undefined, // @ts-ignore — agent support in Node.js agent, }); if (!res.ok) throw new Error(`Gamma ${res.status}`); return res.json(); } return { generate: (body: any) => request("POST", "/generations", body), poll: (id: string) => request("GET", `/generations/${id}`), listThemes: () => request("GET", "/themes"), listFolders: () => request("GET", "/folders"), }; }
Performance Targets
| Operation | Target | Action if Exceeded |
|---|---|---|
| Theme/folder lookup | < 50ms (cached) | Verify cache hit |
| Generation start | < 500ms | Check network latency |
| Full generation (5 cards) | < 30s | Use |
| Full generation (10+ cards) | < 60s | Split into smaller decks |
| Batch of 10 presentations | < 3 min | Use concurrency limit of 3 |
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| High latency on first request | Cold TCP connection | Use keep-alive agent |
| Cache miss storm | Cache expired simultaneously | Stagger TTLs |
| Batch rate limiting | Too many concurrent requests | Reduce concurrency |
| Poll timeout | Complex generation | Increase timeout, simplify content |
Resources
Next Steps
Proceed to
gamma-cost-tuning for credit optimization.