kumo-astro / generators
AGENTS.md4 starsChanged 9 months agoMITView on GitHub
37 component generators creating Figma components from component-registry.json. Registry is source of truth. Parent: See packages/kumo-figma/AGENTS.md for plugin context. Every generator follows this structure: ALL magic numbers and constants MUST live here: Key utilities:
1 other project uses a version of this.
Adopted by
Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data
Most recently taken up by
- cloudflare/kumoword for word, first seen Oct 13, 2026
Other versions1 project uses a version of this.
Word for word · 1
- cloudflare/kumo★ 4.2k100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,439 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository11 other files it gives its agents.
- AGENTS.mdAGENTS.md
- ci/AGENTS.mdAGENTS.md
- packages/kumo/AGENTS.mdAGENTS.md
- packages/kumo-astro/AGENTS.mdAGENTS.md
- packages/kumo-blocks/AGENTS.mdAGENTS.md
- packages/kumo-docs-astro/AGENTS.mdAGENTS.md
- packages/kumo-figma/AGENTS.mdAGENTS.md
- packages/kumo-screenshot-worker/AGENTS.mdAGENTS.md
- packages/kumo/src/components/AGENTS.mdAGENTS.md
- packages/kumo-studio/AGENTS.mdAGENTS.md
- index-knowledgeSkill
The file
We split this AGENTS.md into the rules it gives an agent
10 rules. About 0 are common, 6 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 22
Every generator follows this structure:
- Distinctive: line 96
ALL magic numbers and constants MUST live here:
- Very specific: line 126
Create generators/yourcomponent.ts following 4-step pattern
- Distinctive: line 127
Add testable exports (pure functions)
- Very specific: line 134
Add to EXCLUDED_COMPONENTS in drift-detection.test.ts (with reason)
- Distinctive: line 140
Generator existence: Every registry component has a generator (or is excluded)
- Distinctive: line 145
Shadow centralization: No hardcoded shadow effects
- Very specific: line 146
Opacity centralization: No hardcoded opacity = 0.5
- Distinctive: line 147
RGB centralization: No hardcoded RGB color objects
- Very specific: line 148
Font size usage: Must use FONT_SIZE or FIGMA-SPECIFIC comment
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Figma Generators (src/generators/)
37 component generators creating Figma components from component-registry.json. Registry is source of truth.
Parent: See packages/kumo-figma/AGENTS.md for plugin context.
STRUCTURE
generators/
├── shared.ts # ALL constants (1544 lines) - CRITICAL, see below
├── icon-utils.ts # Icon creation, placeholder, color binding (308 lines)
├── _test-utils.ts # Shared test assertions (345 lines)
├── drift-detection.test.ts # Meta-test: 1733 lines, enforces sync
├── button.ts # Example generator (see pattern below)
├── button.test.ts # Tests for button generator
└── ... (35+ component generators + tests)GENERATOR PATTERN (Canonical 4-Step)
Every generator follows this structure:
1. Imports
import { SPACING, FONT_SIZE, createAutoLayoutFrame, ... } from "./shared";
import { parseTailwindClasses } from "../parsers/tailwind-to-figma";
import registry from "@cloudflare/kumo/ai/component-registry.json";2. Extract Registry Data
const componentProps = registry.components.Button.props;
const variantProp = componentProps.variant as { values: string[]; classes: Record<string, string>; };
const sizeProp = componentProps.size as { ... };3. Testable Exports (Pure Functions - NO Figma API)
// These enable unit testing without Figma runtime
export function getButtonVariantConfig() {
return { values, classes, descriptions, default: variantProp.default };
}
export function getButtonParsedBaseStyles() {
return parseTailwindClasses(baseClasses);
}
export function getButtonParsedVariantStyles(variant: string) {
return parseTailwindClasses(variantProp.classes[variant]);
}
export function getAllButtonVariantData() {
// Aggregates all intermediate data for testing
}4. Generator Function
export async function generateButtonComponents(
page: PageNode,
startY: number,
): Promise<number> {
// 1. Generate ComponentNodes for each variant
const components: ComponentNode[] = [];
for (const variant of variants) {
const component = await createButtonVariant(variant);
components.push(component);
}
// 2. Combine as Figma variants
const componentSet = figma.combineAsVariants(components, page);
componentSet.name = "Button";
// 3. Create light/dark mode sections
const lightSection = createModeSection(page, "Button", "light");
const darkSection = createModeSection(page, "Button", "dark");
// 4. Place in sections
lightSection.frame.appendChild(componentSet);
for (const comp of components) {
darkSection.frame.appendChild(comp.createInstance());
}
// 5. Return next Y position
return startY + totalHeight + SECTION_GAP;
}SHARED.TS (CRITICAL)
ALL magic numbers and constants MUST live here:
| Category | Constants |
| Layout | SECTION_PADDING, SECTION_GAP, SECTION_LAYOUT, GRID_LAYOUT |
| Spacing | SPACING.xs/sm/base/lg |
| Typography | FONT_SIZE.xs/sm/base/lg, FALLBACK_VALUES.fontWeight.* |
| Borders | BORDER_RADIUS.xs/sm/md/lg/xl/full |
| Effects | SHADOWS.xs/sm/lg/dialog/subtle (via getShadowLayer()) |
| Opacity | OPACITY.disabled/backdrop/shortcut |
| Colors | COLORS.placeholder/spinner/border (RGB fallbacks) |
| Variables | VAR_NAMES.text.*, VAR_NAMES.color.* (semantic mapping) |
| Dash | DASH_PATTERN.standard ([4, 4]) |
Key utilities:
createAutoLayoutFrame(config)- Creates frame with auto-layoutcreateTextNode(text, fontSize, fontWeight)- Styled text with Inter font (async)createModeSection(page, name, "light"|"dark")- Creates mode-scoped sectioncreateComponentSectionPair(page, name, startY, width, height)- Light+dark paircreateRowLabel(text, x, y)- Styled label for gridscreateColumnHeaders(headers, y, frame)- Header row for gridsbindFillToVariable(node, variableId)- Binds fill to Figma variablebindFillToVariableWithOpacity(node, varName)- Handles"color/20"opacity suffixgetVariableByName(name)- Looks up variable from kumo-colors collection (cached)getOrCreateVariableWithOpacity(nameWithOpacity)- Creates opacity variants at runtimeapplyCornerRadius(node, radius)- Apply radius by key or number
ADDING A GENERATOR
- Create
generators/yourcomponent.tsfollowing 4-step pattern - Add testable exports (pure functions)
- Register in
code.tsGENERATORS array:{ name: "YourComponent", execute: async (page, y) => ({ nextY: await generateYourComponentComponents(page, y) }) } - Either:
- Create
yourcomponent.test.tsOR - Add to
EXCLUDED_COMPONENTSin drift-detection.test.ts (with reason)
- Create
DRIFT DETECTION
drift-detection.test.ts enforces:
- Generator existence: Every registry component has a generator (or is excluded)
- Code.ts registration: Generator file imported and in GENERATORS array
- Testable exports: Warns if missing
get*Config()orget*Data()functions - No magic numbers: Catches local redeclaration of shared.ts constants
- Import validation: Constants must be imported, not copied
- Shadow centralization: No hardcoded shadow effects
- Opacity centralization: No hardcoded
opacity = 0.5 - RGB centralization: No hardcoded RGB color objects
- Font size usage: Must use
FONT_SIZEorFIGMA-SPECIFICcomment
Excluded components (with reasons): Field, Grid, PageHeader, Popover
ANTI-PATTERNS
| Pattern | Why | Instead |
const PADDING = 16 | Drift detection fails | import { SPACING } from "./shared" |
{ r: 0.5, g: 0.5, b: 0.5 } | Not themeable | COLORS.* or variable binding |
.toBe(16) in tests | Fragile | FONT_SIZE.base or registry values |
| Hardcoding variant names | Registry is truth | Read from registry.components.*.props |
| Skipping testable exports | Untestable | Always export pure get* functions |
NOTES
- 74 files total: 37 generators + 34 tests + 3 utilities
- Largest:
shared.ts(1544 lines),drift-detection.test.ts(1733 lines) - Component coverage: Badge, Banner, Button, Checkbox, Combobox, Dialog, Input, Select, Table, etc.
- Variable binding:
getVariableByName()+bindFillToVariable()for theme-aware colors - Opacity variants: Created at runtime via
getOrCreateVariableWithOpacity("color/20") - Component variant naming:
"variant=primary, size=base, disabled=false"format
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

