Skip to content

Commit a43c8a9

Browse files
rubenmarcusclaude
andauthored
feat: Figma-specific agent prompts, auto-inject tokens, spec cap (#248)
* feat: add Figma-specific agent prompts in context builder When sourceType is 'figma', inject domain-specific guidelines into the agent preamble: auto-layout to flexbox/grid mapping, color token extraction with @theme inline, typography fidelity, constraint conversion, responsive breakpoints, and placeholder images. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: auto-inject Figma design tokens and cap spec size When fetching from Figma in default 'spec' mode, also fetch design tokens (CSS variables) and prepend them to the spec. The agent gets ready-to-use tokens for @theme inline instead of parsing the raw tree. Also pass all Figma CLI options through to fetchFromSource (previously only label/status/limit/issue were passed). Cap in-prompt spec at 15KB to reduce token waste — full spec remains on disk in specs/ directory. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6b57a37 commit a43c8a9

3 files changed

Lines changed: 67 additions & 3 deletions

File tree

src/commands/run.ts

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { formatPresetsHelp, getPreset, type PresetConfig } from '../presets/inde
2020
import { autoInstallSkillsFromTask } from '../skills/auto-install.js';
2121
import { getSourceDefaults } from '../sources/config.js';
2222
import { fetchFromSource } from '../sources/index.js';
23+
import type { SourceOptions } from '../sources/types.js';
2324
import { detectPackageManager, formatRunCommand, getRunCommand } from '../utils/package-manager.js';
2425
import { showWelcome } from '../wizard/ui.js';
2526

@@ -291,17 +292,47 @@ export async function runCommand(
291292
console.log(chalk.dim(` Using default repo: ${projectId}`));
292293
}
293294

294-
const result = await fetchFromSource(options.from, projectId, {
295+
const fetchOptions: SourceOptions = {
295296
label: options.label,
296297
status: options.status,
297298
limit: options.limit,
298299
issue: options.issue,
299-
});
300+
figmaMode: options.figmaMode,
301+
figmaFramework: options.figmaFramework,
302+
figmaFormat: options.figmaFormat,
303+
figmaNodes: options.figmaNodes,
304+
figmaScale: options.figmaScale,
305+
figmaTarget: options.figmaTarget,
306+
figmaPreview: options.figmaPreview,
307+
figmaMapping: options.figmaMapping,
308+
};
309+
310+
const result = await fetchFromSource(options.from, projectId, fetchOptions);
300311

301312
spinner.succeed(`Fetched spec from ${result.source}`);
302313
sourceSpec = result.content;
303314
sourceTitle = result.title;
304315

316+
// Auto-inject design tokens when fetching Figma spec (default mode)
317+
if (
318+
options.from.toLowerCase() === 'figma' &&
319+
(!options.figmaMode || options.figmaMode === 'spec')
320+
) {
321+
try {
322+
const tokensResult = await fetchFromSource(options.from, projectId, {
323+
...fetchOptions,
324+
figmaMode: 'tokens',
325+
figmaFormat: options.figmaFormat || 'css',
326+
});
327+
if (tokensResult.content) {
328+
sourceSpec = `## Design Tokens\n\n${tokensResult.content}\n\n---\n\n${sourceSpec}`;
329+
console.log(chalk.dim(' Auto-injected design tokens into spec'));
330+
}
331+
} catch {
332+
// Tokens fetch failed — proceed with spec only
333+
}
334+
}
335+
305336
// Extract issue reference from metadata for PR linking
306337
if (
307338
result.metadata?.type === 'github' &&
@@ -329,6 +360,22 @@ export async function runCommand(
329360
writeFileSync(specPath, sourceSpec);
330361
console.log(chalk.dim(` Written to: ${specPath}`));
331362

363+
// Cap spec size for agent context (full spec remains on disk in specs/)
364+
const MAX_SPEC_SIZE = 15_000;
365+
if (sourceSpec.length > MAX_SPEC_SIZE) {
366+
console.log(
367+
chalk.yellow(
368+
` Spec is large (${(sourceSpec.length / 1024).toFixed(1)}KB). Trimming to ${(MAX_SPEC_SIZE / 1024).toFixed(0)}KB for agent context.`
369+
)
370+
);
371+
const truncated = sourceSpec.slice(0, MAX_SPEC_SIZE);
372+
const lastSection = truncated.lastIndexOf('\n## ');
373+
sourceSpec =
374+
lastSection > MAX_SPEC_SIZE * 0.7
375+
? `${truncated.slice(0, lastSection)}\n\n[Spec truncated — see specs/ directory for full design specification]`
376+
: `${truncated}\n\n[Spec truncated — see specs/ directory for full design specification]`;
377+
}
378+
332379
// Prompt for project location when fetching from integration sources
333380
// Skip if --auto or --output-dir was provided
334381
const integrationSources = ['github', 'linear', 'notion', 'todoist'];

src/loop/context-builder.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export interface ContextBuildOptions {
3535
skipPlanInstructions?: boolean;
3636
/** Iteration log content from .ralph/iteration-log.md (previous iteration summaries) */
3737
iterationLog?: string;
38+
/** Source integration type (github, linear, figma, notion, file) for source-specific prompts */
39+
sourceType?: string;
3840
}
3941

4042
export interface BuiltContext {
@@ -251,7 +253,21 @@ Design quality (IMPORTANT):
251253
- If no spec exists, choose ONE clear design direction (bold/minimal/retro/editorial/playful) and commit to it
252254
- Use a specific color palette with max 3-4 colors, not rainbow gradients
253255
- Avoid generic AI aesthetics: no purple-blue gradient backgrounds/text, no glass morphism/neumorphism, no Inter/Roboto defaults — pick distinctive typography (e.g. DM Sans, Playfair Display, Space Mono)
254-
`;
256+
${
257+
opts.sourceType === 'figma'
258+
? `
259+
Figma-to-code guidelines (CRITICAL — your spec comes from a Figma design file):
260+
- AUTO-LAYOUT → FLEXBOX/GRID: "horizontal" = \`display: flex; flex-direction: row\`. "Vertical" = \`flex-direction: column\`. "Wrap" = \`flex-wrap: wrap\`. Use gap for item spacing.
261+
- COLORS: If the spec includes a "Design Tokens" section with CSS variables, put them in \`@theme inline { }\` and use Tailwind utilities (e.g. \`bg-primary\`, \`text-accent/80\`). If not, extract colors from the spec and create the @theme block yourself.
262+
- TYPOGRAPHY: Use the EXACT font names from the spec. Add Google Fonts import if needed. Do NOT substitute with generic fonts.
263+
- CONSTRAINTS: "Fill container" = \`width: 100%\` or \`flex: 1\`. "Fixed" = exact px value. "Hug contents" = \`width: fit-content\`.
264+
- SPACING: Apply padding/margin exactly as specified in the spec (top right bottom left notation).
265+
- RESPONSIVE: The Figma spec shows a single breakpoint. Add responsive breakpoints: stack columns on mobile, adjust font sizes, add appropriate padding.
266+
- IMAGES: Use placeholder images from https://placehold.co with exact dimensions from the spec (e.g. \`https://placehold.co/400x300\`).
267+
- FIDELITY: Match the design EXACTLY — don't add extra elements, animations, or decorations not in the spec.
268+
`
269+
: ''
270+
}`;
255271

256272
// Inject iteration log for iterations 2+ (gives agent memory of what happened before)
257273
const iterationLogSection =

src/loop/executor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,7 @@ export async function runLoop(options: LoopOptions): Promise<LoopResult> {
816816
specSummary,
817817
skipPlanInstructions: options.skipPlanInstructions,
818818
iterationLog,
819+
sourceType: options.sourceType,
819820
});
820821
const iterationTask = builtContext.prompt;
821822

0 commit comments

Comments
 (0)