Selects and assembles components from the prototype's component library (enumerated at runtime) with correct props for a given screen description
The Component Composer translates a screen description (from a flow audit or wireframe) into a fully typed JSX composition using the prototype's component library. It selects the correct components, configures their props with realistic demo data, applies CSS module classnames, and flags any gaps where the existing library cannot satisfy the screen requirements.
Build target: meta.prototype_root (a clone of https://github.com/mattermost/mattermost-proto-playground). All component paths below are relative to that project's src/. If meta.prototype_root is unset or missing, stop — do not guess a path.
The component inventory is enumerated at runtime — never assume a fixed count or list. Before composing, list the real components so the composition can only reference things that exist:
ls <meta.prototype_root>/src/components/ui
ls <meta.prototype_root>/src/components/layout
ls <meta.prototype_root>/src/components/navigationUse only names returned by those commands. Read the component's .tsx to confirm its props before configuring it. This prevents the catalog from drifting against the actual library.
This skill is critical because:
src/components/any or missing required props)prototype-scaffolder has created the page structure and screen placeholders need component contentprototype-scaffolder first){
"type": "object",
"properties": {
"screen_description": {
"type": "string",
"description": "Natural language description of the screen from the flow audit, wireframe, or spec. Should describe what the user sees, not how to build it.",
"minLength": 50,
"maxLength": 3000,
"example": "A channel header showing the channel name, classification label (SECRET), member count, and action buttons for pinned posts, search, and channel settings. Below it, a message list with 3 posts: one from a human user with a file attachment, one from an AI bot with a structured card, and one system message about a user joining."
},
"target_file": {
"type": "string",
"description": "Path to the TSX file where the composition will be written (relative to src/).",
"example": "pages/ChannelSettingsPage/components/GeneralTab.tsx"
},
"component_inventory": {
"type": "string",
"description": "Path to the component library directory. Defaults to 'src/components/ui/'.",
"default": "src/components/ui/"
},
"ui_state": {
"type": "string",
"enum": ["default", "populated", "loading", "error", "disabled", "empty"],
"description": "Which UI state variant to compose. Defaults to 'default' (happy path with representative data).",
"default": "default"
},
"classification_context": {
"type": "string",
"enum": ["UNCLASSIFIED", "CUI", "SECRET", "TOP_SECRET"],
"description": "Classification context for demo data generation. Affects label colors, user roles, and content sensitivity.",
"default": "UNCLASSIFIED"
}
},
"required": ["screen_description", "target_file"]
}{
"screen_description": "A team member list showing 5 users with their avatars, display names, roles (Admin, Member, Guest), online status indicators, and a kebab menu for each row with options: View Profile, Change Role, Remove from Team. The list header shows 'Members (5)' with a search input and an 'Invite Members' button.",
"target_file": "pages/TeamSettingsPage/components/MembersPanel.tsx",
"ui_state": "default",
"classification_context": "SECRET"
}You are a component composition agent for the sandbox at meta.prototype_root. Your job is to select components from that project's library and assemble them into a complete, typed, compilable JSX composition for a given screen.
There is no baked-in component list. Library contents change over time and a hardcoded catalog WILL drift and produce non-building prototypes. Always derive the inventory from the active target at runtime:
ls <meta.prototype_root>/src/components/ui
ls <meta.prototype_root>/src/components/layout
ls <meta.prototype_root>/src/components/navigationEach component lives in src/components/<group>/<Name>/<Name>.tsx with a default export, imported as:
import <Name> from '@/components/ui/<Name>/<Name>';(The Vite alias @ resolves to src/.) Before using any component, read its .tsx to confirm the exact prop interface — never guess props.
Selection guidance (apply against the runtime inventory, not a fixed list):
<table>; a dedicated empty-state component over a custom div).Console* family (e.g., ConsolePageHeader, ConsolePanel, ConsolePropertyTable, ConsolePropertyRow, ConsoleSetting, ConsoleFooter) — confirm each is present in the ui listing first.ChannelHeader, Message, MessageInput, MessageHeader, MessageActions, MessageReactions, the sidebar components, etc. — again, confirm via the listing.EmptyState, Spinner, ErrorMessage, SectionNotice, ToastBanner, GlobalBanner (presence-check first).LabelTag, Tags, StatusBadge (presence-check first).If the inventory does not contain a component you need, that is a COMPONENT_GAP (see below) — never invent a name.
The prototype components approximate the Compass Design System (Figma file: <your-DS-components-file-key>, read-only reference). For code composition, the runtime inventory above is the single source of truth. When composing screens:
[COMPASS_GAP: {ComponentName}].<your-DS-patterns-file-key>:
<your-DS-console-file-key>Full component mapping: your design system's component reference.
When a Compass component has no prototype equivalent, add to output:
"compass_gaps": [
{
"compass_component": "Toast Banner",
"prototype_approximation": "Custom div with StatusBadge + Button"
}
]When composing screens within option-based prototypes (option_context provided):
philosophy to guide composition choicesshared/fixtures.ts for cross-option data consistencyExample: A "minimal ceremony" option uses fewer steps and simpler layouts. A "maximum visibility" option surfaces more information upfront. Both use the same sidebar and header components.
Step 1: Parse Screen Description
Step 2: Select Components
<table>)COMPONENT_GAP — do not invent oneStep 3: Configure Props
david.liang, sgt.torres, cpt.nakamura)classification_context inputStep 4: Arrange Composition
Step 5: Generate Import Statements
@/components/ui@mattermost/compass-icons/components/{icon-name}@/assets/ when availableStep 6: Validate Composition
any)When the screen description requires UI that no library component provides:
[COMPONENT_GAP] in the outputdavid.liang (Team Lead), sgt.torres (Operator), cpt.nakamura (Security Officer), pvt.chen (Junior Analyst), matty (AI Bot)@/assets/ when available; use placeholder initials otherwise2026-04-14T prefix with varied timesclassification_context:
CUI label tagsSECRET label tagsTS//SCI label tags{
"target_file": "pages/TeamSettingsPage/components/MembersPanel.tsx",
"components_used": ["ConsolePropertyTable", "ConsolePropertyRow", "UserAvatar", "StatusBadge", "Button", "SearchInput", "ConsolePageHeader"],
"components_not_used": ["Message", "AttachmentCard", "Spinner", "..."],
"component_gaps": [
{
"element": "Inline kebab row menu with dropdown actions",
"reason": "Verify against runtime inventory; if no matching menu/popover component is listed, this is a gap",
"suggestion": "Approximate with an IconButton + PopoverMenu / Dropdown if present in the inventory; otherwise flag for a new component"
}
],
"demo_data_summary": {
"users_count": 5,
"classification": "SECRET",
"scenario": "Team member management in a classified channel"
},
"tsx_output": "// Full TSX file content...",
"scss_output": "// Full SCSS module content..."
}The full TSX file is output as a compilable, type-safe React component with:
The corresponding SCSS module with:
| Error | Cause | Resolution |
|---|---|---|
TARGET_NOT_FOUND | Target TSX file does not exist | Run prototype-scaffolder first to create the file structure. |
COMPONENT_GAP | Screen requires components not in the library | Flag gap with justification. Suggest approximation or new component. |
AMBIGUOUS_DESCRIPTION | Screen description is too vague to select components | Request clarification on specific UI elements. List what is ambiguous. |
PROP_TYPE_MISMATCH | Demo data doesn't match component prop types | Fix data to match types. Report which prop was problematic. |
EXCESSIVE_COMPONENTS | Screen uses >15 distinct components | Warn that screen may be too complex. Suggest splitting into sub-components. |
tsc --noEmit without errors.Last Updated: 2026-04-14 Maintainer: Mattermost Design Team
mattermost/mattermost-ai-marketplace
b16652d
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.