Symbiote components
Agent skills for Stitch MCP, Project Graph MCP, and Symbiote.js component generation.
npx -y skills add rnd-pro/stitch-skills --skill symbiote-componentsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Converts Stitch designs into modular Symbiote.js 3.x components using triple-file architecture, CSS custom properties, and Project Graph MCP validation.
SKILL.md
11.5 KB, as published. Nobody here has run it
Stitch to Symbiote Components
You are a frontend engineer focused on transforming Stitch designs into clean Symbiote.js 3.x components. You follow a modular triple-file architecture and use Project Graph MCP tools for automated quality checks.
Key references:
- Official API: AI_REFERENCE.md
- Quick reference:
resources/symbiote-3x-reference.md(at project root) - Global styles:
resources/global-styles-template.md(at project root)
Package Boundaries
Use the package that owns the contract you are consuming:
@symbiotejs/[email protected]— core component runtime,Symbiote,html,css,PubSub,AppRouter, SSR primitives, and WebMCP-capable runtime metadata.[email protected]— reusable UI components, graph/layout/provider metadata, tokens, rules, schemas,custom-elements.json, and WebMCP UI descriptors.[email protected]— runtime engines, workflow execution, handlers, packs, persistence, and server/runtime CLI contracts.
Do not introduce symbiote-node for new projects. Treat it as a terminal migration facade only when maintaining a legacy consumer that explicitly tests compatibility.
Retrieval and Networking
- Namespace discovery: Run
list_toolsto find the Stitch MCP prefix (e.g.,mcp_StitchMCP_). - Metadata fetch: Call
[prefix]get_screento retrieve the design JSON. - Asset download: Use
web_fetchorread_url_contentto download HTML fromhtmlCode.downloadUrl. - Visual audit: Check
screenshot.downloadUrlto confirm the design intent and layout details.
Architectural Rules
Triple-File Standard (MANDATORY)
Every component MUST be split into exactly three files:
src/components/TaskCard/
├── TaskCard.js — Class logic only (extends Symbiote)
├── TaskCard.tpl.js — Template (html tagged template)
└── TaskCard.css.js — Styles (css tagged template)
Core Conventions
- Custom Elements: Every component is a Custom Element registered with
.reg('tag-name') - ESM only: Use
import/export. Neverrequire() - No Tailwind: Use native CSS with custom properties (design tokens from
DESIGN.md) - No BEM: Use custom tag names and attribute selectors as CSS selectors
- No wrapper divs: The custom tag IS the wrapper element
- No CSS frameworks: Pure CSS with modern nesting
- JSDoc in English: Document in JSDoc, no TypeScript files
- Template outside class:
MyComp.template = html\...`` — NEVER inside the class body
Style Mapping
- Extract colors, spacing, and typography from the Stitch HTML
<head>or inline styles - Map all values to CSS custom properties defined in
DESIGN.md(or create them if missing) - Use
rootStylesfor Light DOM components by default - Use
shadowStyles/ Shadow DOM only when real isolation is required: third-party CSS containment, hostile or unknown markup, embedded previews/demos, or browser API encapsulation - If the issue is styling, themes, selector conflicts, or uncertainty, first solve it with Symbiote bindings, CSS custom properties, slots, context, provider tokens, and component composition before choosing Shadow DOM
Data Decoupling
- Move all static text, image URLs, and list data into separate data files
- Use local
init$for component-specific state - Use
*prefix +ctxattribute for shared context between sibling components - Use named context (
PubSub.registerCtx) for global application state (APP/propsyntax) - See
resources/symbiote-3x-reference.mdfor PubSub and Shared Context patterns
Element References
- Use
${{ref: 'name'}}in templates for DOM element access - Access via
this.ref.nameinrenderCallback() - Prefer state bindings over direct DOM manipulation
Slots (Light DOM)
- Import
slotProcessorfrom@symbiotejs/symbiote/core/slotProcessor.js - Add in constructor:
this.templateProcessors.add(slotProcessor) - Use
<slot name="header"></slot>and<slot></slot>in templates - See
resources/symbiote-3x-reference.mdfor full example
WebMCP Metadata
Use WebMCP documentation for agents in bounded, contract-level form. Component metadata should describe names, descriptions, input schemas, SSR class, visibility, and permission hints. Do not turn WebMCP descriptors into long prose docs or hidden policy systems.
Component Template
Use resources/component-template.js as a starting point. Replace StitchComponent with the actual component name.
Template File Pattern (Component.tpl.js)
import { html } from '@symbiotejs/symbiote';
export const template = html`
<header>
<h2>{{title}}</h2>
<span>{{description}}</span>
</header>
<div ${{onclick: 'onAction'}}>
</div>
`;
NOTE: Light DOM slots require explicit
slotProcessorsetup in v3.x:import { slotProcessor } from '@symbiotejs/symbiote/core/slotProcessor.js'; constructor() { super(); this.templateProcessors.add(slotProcessor); }
Styles File Pattern (Component.css.js)
import { css } from '@symbiotejs/symbiote';
export const styles = css`
my-component {
display: block;
padding: var(--spacing-md);
background: var(--color-surface);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
& header {
margin-block-end: var(--spacing-sm);
}
& h2 {
font-size: var(--font-size-lg);
font-weight: var(--font-weight-semibold);
color: var(--color-text);
}
&:hover {
box-shadow: var(--shadow-md);
transition: box-shadow var(--transition-fast);
}
&[hidden] {
display: none !important;
}
}
`;
Logic File Pattern (Component.js)
import Symbiote from '@symbiotejs/symbiote';
import { template } from './Component.tpl.js';
import { styles } from './Component.css.js';
export class MyComponent extends Symbiote {
init$ = {
title: '',
description: '',
// Event handlers: init$ arrow functions checked first, then class methods as fallback
onAction: () => {
console.log('Action triggered');
},
};
}
MyComponent.template = template;
MyComponent.rootStyles = styles;
MyComponent.reg('my-component');
Key v3.x Features
Event handler resolution: For on* bindings, Symbiote first looks in init$, then falls back to class methods:
class MyComponent extends Symbiote {
init$ = { onClick: () => console.log('via init$') };
onSubmit() { console.log('via class method fallback'); }
}
Computed properties (+ prefix, auto-tracked):
init$ = {
a: 1,
b: 2,
'+sum': () => this.$.a + this.$.b, // recalculates when a or b change
};
Element references (ref):
MyComponent.template = html`
<input ${{ref: 'nameInput'}}>
<button ${{ref: 'submitBtn', onclick: 'onSubmit'}}>Submit</button>
`;
// In renderCallback: this.ref.nameInput.focus();
Dev mode (enable during development):
Symbiote.devMode = true; // warns about unresolved bindings, missing ctx, etc.
Exit animations (animateOut):
import { animateOut } from '@symbiotejs/symbiote';
// Sets [leaving] attribute, waits for CSS transitionend, then removes element
my-item {
transition: opacity 0.3s;
&[leaving] { opacity: 0; }
}
Execution Steps
- Read DESIGN.md: If exists, load the CSS custom properties and component patterns.
- Download Stitch HTML: Fetch the HTML source from the screen's
htmlCode.downloadUrl. - Analyze structure: Identify repeating UI patterns, sections, and interactive elements.
- Plan components: Map each pattern to a Symbiote component with a custom element tag name.
- Create data layer: Extract static content into data files or named contexts.
- Draft components: Create each component using the triple-file structure.
- Wire entry point: Create a root component (e.g.,
app-root) that composes all sub-components. - Validate with Project Graph MCP (see
resources/project-graph-workflow.mdat project root):get_skeleton(path)— verify all components appear, check structureget_full_analysis(path)— target Health Score ≥ 80check_custom_rules(path)— auto-detects Symbiote, applies convention rulesget_dead_code(path)— cleanup unused exports after refactoringget_undocumented(path)— verify JSDoc coverage
- Add test annotations to interactive handlers:
/** * @test click: Click the action button * @expect visual: Status badge changes color */ - Run test checklist:
get_pending_tests(path)— list all @test/@expect annotations- Execute each test step (browser tool for UI)
mark_test_passed(testId)/mark_test_failed(testId, reason)get_test_summary(path)— verify all tests pass
- Visual verify: Compare the assembled page against the Stitch screenshot.
Conversion Rules: Stitch HTML → Symbiote
HTML Structure
| Stitch HTML | Symbiote Equivalent |
|---|---|
<div class="card"> | <ui-card> (Custom Element) |
<div class="card-header"> | Remove wrapper if unnecessary, use <header> inside template |
class="text-lg font-bold" | CSS: font-size: var(--font-size-lg); font-weight: var(--font-weight-bold); |
class="bg-blue-500" | CSS: background: var(--color-primary); |
class="rounded-lg" | CSS: border-radius: var(--radius-lg); |
class="shadow-md" | CSS: box-shadow: var(--shadow-md); |
class="p-4" | CSS: padding: var(--spacing-md); |
class="flex gap-4" | CSS: display: flex; gap: var(--spacing-md); |
class="hidden" | Attribute binding: ${{'@hidden': 'isHidden'}} |
onclick="..." | Binding: ${{onclick: 'handlerName'}} |
Interactivity
| Pattern | Symbiote Implementation |
|---|---|
| Show/Hide | ${{'@hidden': '!isVisible'}} in template, isVisible in init$ |
| Dynamic text | {{propertyName}} in template |
| Click handler | ${{onclick: 'onClickHandler'}} → method in class or init$ |
| List rendering | ${{itemize: 'items'}} with <template> inside (use ^ for parent handlers) |
| Custom item tag | ${{itemize: 'items', 'item-tag': 'my-item'}} (inside binding block, not HTML attribute) |
| Form input | ${{oninput: 'onInput'}} with ref for value |
Troubleshooting
- Styles not applied: Ensure
rootStylesis set OUTSIDE the class body - Template not rendering: Ensure
templateis assigned via the static setter, not inside the class - Events not firing in lists: Use
^prefix for parent handlers in itemize templates:${{onclick: '^parentHandler'}} - Hidden not working: Add
&[hidden] { display: none !important; }if component has custom display
Quality Checklist
Before delivering, verify all items from resources/architecture-checklist.md:
- Triple-file split for every component
- No Tailwind classes anywhere
- All colors use CSS custom properties
- All spacing uses CSS custom properties
- Custom tag name selectors (no BEM classes)
- Native CSS nesting used
- No unnecessary wrapper divs
- Template assigned outside class body
- Event handlers properly bound
-
Project Graph MCPanalysis passes