Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Execute Framer primary workflow: Core Workflow A. Use when implementing primary use case, building main features, or core integration tasks. Trigger with phrases like "framer main workflow", "primary task with framer".
.claude/skills/jeremylongshore-framer-core-workflow-a/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 13% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 24% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 56% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 65% | 0% |
| case-09 | ✗→✓ | ▲ Improved | -12% | 0% |
Build a Framer plugin that syncs external data into CMS Managed Collections. Managed Collections are plugin-controlled — your plugin creates the schema and populates items. This is the primary integration pattern for connecting Framer to external CMSes, databases, or APIs.
framer-install-auth setuptsx// src/App.tsx — CMS sync plugin import { framer } from 'framer-plugin'; import { useState } from 'react'; framer.showUI({ width: 340, height: 400, title: 'Content Sync' }); export function App() { const [status, setStatus] = useState(''); const syncCollection = async () => { setStatus('Fetching data...'); const response = await fetch('https://jsonplaceholder.typicode.com/posts'); const posts = await response.json(); setStatus('Creating collection...'); const collection = await framer.createManagedCollection({ name: 'Blog Posts', fields: [ { id: 'title', name: 'Title', type: 'string' }, { id: 'body', name: 'Body', type: 'formattedText' }, { id: 'author', name: 'Author', type: 'string' }, { id: 'slug', name: 'Slug', type: 'slug', userEditable: false }, ], }); setStatus(`Syncing ${posts.length} items...`); const items = posts.slice(0, 20).map((post: any) => ({ fieldData: { title: post.title, body: `<p>${post.body}</p>`, author: `User ${post.userId}`, slug: post.title.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 50), }, })); await collection.setItems(items); setStatus(`Synced ${items.length} posts`); framer.notify(`Synced ${items.length} blog posts`); }; return ( <div style={{ padding: 16 }}> <h3>Blog Post Sync</h3> <button onClick={syncCollection} style={{ width: '100%', padding: 8 }}>Sync Now</button> {status && <p style={{ marginTop: 8, fontSize: 13, color: '#666' }}>{status}</p>} </div> ); }
typescript// Framer CMS field types reference const fields = [ { id: 'title', name: 'Title', type: 'string' as const }, { id: 'content', name: 'Content', type: 'formattedText' as const }, { id: 'price', name: 'Price', type: 'number' as const }, { id: 'featured', name: 'Featured', type: 'boolean' as const }, { id: 'publishDate', name: 'Published', type: 'date' as const }, { id: 'heroImage', name: 'Hero', type: 'image' as const }, { id: 'category', name: 'Category', type: 'enum' as const, cases: [ { id: 'tech', name: 'Technology' }, { id: 'design', name: 'Design' }, ]}, { id: 'slug', name: 'Slug', type: 'slug' as const, userEditable: false }, ];
typescriptasync function incrementalSync(collection: ManagedCollection, newData: any[]) { const existing = await collection.getItems(); const existingMap = new Map(existing.map(i => [i.fieldData.slug, i])); const toUpsert = newData.map(item => { const match = existingMap.get(item.slug); return match ? { ...item, id: match.id } : item; }); await collection.setItems(toUpsert); }
typescript// Read from user-created CMS collections (not plugin-managed) const collections = await framer.getCollections(); for (const col of collections) { if (col.type === 'unmanaged') { const items = await col.getItems(); console.log(`${col.name}: ${items.length} items`); } }
| Error | Cause | Solution | |-------|-------|----------| | Collection exists | Duplicate name | Use getManagedCollection() first | | Invalid field type | Wrong type string | Use: string, formattedText, number, boolean, date, image, enum, slug | | Image upload failed | URL not public | Ensure images are publicly accessible | | setItems timeout | Too many items | Batch into chunks of 100 |
For code components and overrides, see framer-core-workflow-b.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 17,558 | 22,318 | +27% | 1 | 1 | 0% | 3,558 | 5,051 | +42% | 0 | 0 | — |
case-02 | fail→fail | 25,708 | 32,361 | +26% | 1 | 1 | 0% | 4,142 | 7,197 | +74% | 0 | 0 | — |
case-03 | fail→pass | 17,279 | 10,988 | -36% | 1 | 1 | 0% | 2,156 | 2,435 | +13% | 0 | 0 | — |
case-04 | fail→pass | 13,924 | 8,794 | -37% | 1 | 1 | 0% | 1,638 | 2,029 | +24% | 0 | 0 | — |
case-05 | fail→pass | 12,642 | 9,856 | -22% | 1 | 1 | 0% | 1,393 | 2,178 | +56% | 0 | 0 | — |
case-06 | pass→pass | 13,942 | 11,949 | -14% | 1 | 1 | 0% | 1,616 | 2,628 | +63% | 0 | 0 | — |
case-07 | fail→fail | 7,876 | 8,348 | +6% | 1 | 1 | 0% | 1,425 | 2,661 | +87% | 0 | 0 | — |
case-08 | fail→pass | 12,630 | 5,329 | -58% | 1 | 1 | 0% | 1,374 | 2,264 | +65% | 0 | 0 | — |
case-09 | fail→pass | 21,242 | 11,466 | -46% | 1 | 1 | 0% | 2,680 | 2,361 | -12% | 0 | 0 | — |
case-10 | fail→pass | 13,464 | 12,426 | -8% | 1 | 1 | 0% | 1,488 | 2,476 | +66% | 0 | 0 | — |
case-11 | pass→pass | 8,997 | 6,911 | -23% | 1 | 1 | 0% | 1,601 | 2,579 | +61% | 0 | 0 | — |
case-12 | pass→pass | 7,265 | 6,092 | -16% | 1 | 1 | 0% | 1,331 | 2,363 | +78% | 0 | 0 | — |
case-13 | fail→fail | 10,393 | 13,540 | +30% | 1 | 1 | 0% | 1,904 | 2,863 | +50% | 0 | 0 | — |
case-14 | pass→pass | 18,800 | 13,381 | -29% | 1 | 1 | 0% | 2,334 | 2,781 | +19% | 0 | 0 | — |
case-15 | pass→pass | 4,244 | 2,365 | -44% | 1 | 1 | 0% | 771 | 1,693 | +120% | 0 | 0 | — |
case-16 | pass→pass | 11,430 | 10,550 | -8% | 1 | 1 | 0% | 1,902 | 2,293 | +21% | 0 | 0 | — |
case-17 | pass→pass | 11,662 | 9,201 | -21% | 1 | 1 | 0% | 1,256 | 1,992 | +59% | 0 | 0 | — |
case-18 | pass→pass | 8,239 | 8,672 | +5% | 1 | 1 | 0% | 1,585 | 2,875 | +81% | 0 | 0 | — |
case-19 | pass→pass | 13,962 | 13,216 | -5% | 1 | 1 | 0% | 1,629 | 2,735 | +68% | 0 | 0 | — |
case-20 | pass→pass | 16,776 | 8,183 | -51% | 1 | 1 | 0% | 1,885 | 3,186 | +69% | 0 | 0 | — |
case-21 | pass→pass | 15,201 | 17,969 | +18% | 1 | 1 | 0% | 2,257 | 4,265 | +89% | 0 | 0 | — |
case-22 | pass→pass | 18,835 | 19,000 | +1% | 1 | 1 | 0% | 3,010 | 4,284 | +42% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +27 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.