Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions domains/ui/knowledge/agentic-design-system-strategy.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,36 +29,38 @@ One knowledge layer, three deliveries. MMDS holds tokens, components, and patter

| Moment | What happens |
| :---- | :---- |
| **Create** | Agents read current MMDS guidance before building — through skills, Storybook MCP, Figma MCP, and Code Connect. |
| **Create** | Agents read current MMDS guidance before building — through skills, installed package types, the hosted Storybook components manifests, and Figma MCP with Code Connect when connected. |
| **Review** | Deterministic checks (ESLint, fitness functions) plus agentic review for judgment calls. |
| **Audit** | Recurring queries across existing screens to find drift, custom UI, and documentation gaps. |

## Producer / consumer split

- **Consumer skills** (`ui-development` repo overlays) route agents to current MMDS guidance for product UI create and review workflows.
- **Provider skills** (future `design-system` domain) support MMDS authoring, release, and documentation maintenance.
- **Storybook MCP** (`storybook-broker-mcp`) is the preferred delivery mechanism for current MMDS knowledge in coding agents. Package exports and consumer Tailwind configuration are the ordered fallback when the broker is unavailable.
- **Baseline delivery** needs no MCP server: the installed package types in the consumer repo, the hosted Storybook components manifests ([React](https://metamask.github.io/metamask-design-system/manifests/components.json), [React Native](https://metamask.github.io/metamask-design-system/react-native/manifests/components.json)), and the consumer Tailwind configuration. Installed types win when sources disagree, because the manifests track MMDS `main`.
- **Storybook MCP** (`storybook-broker-mcp`, via Context Forge) is optional. Agents may use it when it is already configured and responds, but skills must never depend on it.

## Foundation workstreams

1. **Thin consumer gateway skills** — Refine `ui-development` overlays into stable routers (Create + Review) instead of static component inventories.
2. **Storybook MCP integration** — Treat Context Forge's preconfigured `storybook-broker-mcp` as the primary source; document explicit fallback behavior without embedding setup instructions in skills.
3. **MMDS source and broker readiness** — Keep Storybook documentation, exports, and broker surfaces current for agent consumption.
2. **No-MCP baseline** — Keep the installed types, hosted components manifests, and consumer Tailwind configuration sufficient on their own. Storybook MCP is an optional extra, never a prerequisite, and skills carry no setup instructions for it.
3. **MMDS source readiness** — Keep type JSDoc (including `@deprecated`), READMEs, stories, and the published components manifests current for agent consumption.
4. **Automated alignment checks** — Extend CI and review workflows to validate tokens, components, and patterns where feasible.
5. **Provider-side skills** — Add a `design-system` domain and `metamask-design-system` maintainer overlay in the skills repo.

## Horizon

| Horizon | Focus |
| :---- | :---- |
| **Now** | Build the shared knowledge path and establish quality baselines — point MetaMask Skills to Storybook MCP, begin Figma/React/React Native alignment, expand Code Connect, audit MMDS and product usage. |
| **Now** | Build the shared knowledge path and establish quality baselines — point MetaMask Skills at installed types and the hosted components manifests, begin Figma/React/React Native alignment, expand Code Connect, audit MMDS and product usage. |
| **Next** | Operationalize Create, Review, and Audit in normal delivery — enable the gateway by default in Extension and Mobile, run MMDS-focused review, load relevant skills per UI PR, run recurring audits. |
| **Later** | Build a trusted feedback and remediation loop — agents create issues or PRs for alignment gaps, automate low-risk fixes, retain human approval for judgment calls. |

## Principles for skills

- MMDS is the default; intentional documented custom UI is allowed.
- Skills are gateways and durable constraints, not second copies of MMDS documentation.
- Do not maintain static component inventories, deprecated-name lists, or MCP setup instructions in consumer skills.
- Query current Storybook guidance before choosing components, APIs, tokens, or patterns.
- When Storybook MCP is unavailable, follow the ordered fallback defined in the relevant repo overlay.
- Skills must work with no MCP server connected.
- Do not put release-pinned inventories, version pins, prop lists, or MCP setup instructions in skills. Point at the installed package and the hosted manifests instead.
- Read the installed types before choosing components, APIs, tokens, or patterns. When anything disagrees with them, the installed types win.
- Inline only durable rules that agents need and cannot read elsewhere (for example Active Design Brain rules). Link to Proposed rules; do not enforce them.
55 changes: 35 additions & 20 deletions domains/ui/skills/component-scaffold/repos/metamask-mobile.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Two systems coexist in the repo:

### Layer 1 — `@metamask/design-system-react-native` (MMDS, npm package) ✅ Always use first

The only correct choice for new component primitives. Exports `Box`, `Text`, `BottomSheet`, `BottomSheetHeader`, `BottomSheetFooter`, `ButtonBase`, `ButtonIcon`, `HeaderStandard`, `Icon`, `Skeleton`, `Tag`, and more.
The only correct choice for new component primitives (`Box`, `Text`, `Button`, `ButtonBase`, `Icon`, `ListItem`, `BottomSheet`, and more). For the current inventory and deprecations, use the [React Native components manifest](https://metamask.github.io/metamask-design-system/react-native/manifests/components.json) as described in `ui-development`.

Before writing any UI, verify what the installed version actually exports — the package changes frequently:

Expand All @@ -64,7 +64,15 @@ node_modules/@metamask/design-system-react-native/dist/components/index.d.ts
node_modules/@metamask/design-system-react-native/src/components/index.ts
```

The installed package is the source of truth, not this skill's examples.
The installed package is the source of truth, not this skill's examples. Read props from `dist/components/<Component>/<Component>.types.d.cts`. For behavior and examples, read the component README on GitHub at the release tag (READMEs are not in the npm package):

```
https://github.com/MetaMask/metamask-design-system/blob/@metamask/design-system-react-native@<installed version>/packages/design-system-react-native/src/components/<Component>/README.md
```

Take `<installed version>` from `node_modules/@metamask/design-system-react-native/package.json`. When a README and the types disagree, the types win. No MCP server is needed; if Storybook MCP happens to be configured it is optional, so never block scaffolding on it.

Do not add new usage of anything marked `@deprecated` in the installed types or in the manifest's `jsDocTags.deprecated`.

For local visual testing of a component in isolation, see `docs/readme/storybook.md`.

Expand Down Expand Up @@ -128,12 +136,25 @@ import {

### Interactive / pressed state

`ButtonBase` takes pressed styling through a `twClassName` function. Its `style` prop is a plain style, so a `style={({ pressed }) => ...}` function does not type-check:

```tsx
<ButtonBase
onPress={onPress}
twClassName={(pressed) => `w-full ${pressed ? 'bg-pressed' : 'bg-default'}`}
>
{strings('foo.action')}
</ButtonBase>
```

For a custom pressable container, use `Pressable` with `tw.style()`:

```tsx
import { useTailwind } from '@metamask/design-system-twrnc-preset';

const tw = useTailwind();

<ButtonBase
<Pressable
style={({ pressed }) =>
tw.style('w-full flex-row items-center', pressed && 'bg-pressed')
}
Expand All @@ -144,14 +165,13 @@ const tw = useTailwind();

## 5. Bottom sheet specifics

1. Apply `useElevatedSurface()` to the `BottomSheet`'s `twClassName` — required for pure-black theme support:
1. Use the MMDS `BottomSheet`, `BottomSheetHeader`, and `BottomSheetFooter`. The sheet surface already uses the `bg-elevated1` token, so do not add a surface class unless the design puts the sheet on a different surface (then pass a token class such as `twClassName="bg-default"`):

```tsx
import { useElevatedSurface } from '../../../../util/theme/themeUtils'; // adjust depth

const surfaceClass = useElevatedSurface();

<BottomSheet twClassName={surfaceClass}>
<BottomSheet ref={sheetRef} goBack={navigation.goBack}>
<BottomSheetHeader onClose={handleClose}>{strings('foo.title')}</BottomSheetHeader>
{/* content */}
</BottomSheet>
```

2. `ScrollView` inside a `BottomSheet` must come from `react-native-gesture-handler` — the standard React Native `ScrollView` will not scroll on Android inside a gesture-managed bottom sheet:
Expand All @@ -176,7 +196,7 @@ import { strings } from '../../../../locales/i18n'; // adjust depth to file loca
{strings('namespace.key')}
```

Add new keys to `app/locales/languages/en.json` only. Crowdin picks up new English strings automatically after the PR merges — do not edit other language files manually.
Add new keys to `locales/languages/en.json` (repo root) only. Crowdin picks up new English strings automatically after the PR merges — do not edit other language files manually.

---

Expand All @@ -187,7 +207,7 @@ Add new keys to `app/locales/languages/en.json` only. Crowdin picks up new Engli
Example from `app/components/UI/Compliance/AccessRestrictedModal/AccessRestrictedModal.tsx`:
```tsx
import { strings } from '../../../../../locales/i18n';
import { useElevatedSurface } from '../../../../util/theme/themeUtils';
import { AccessRestrictedModalProps } from './AccessRestrictedModal.types';
```

---
Expand Down Expand Up @@ -255,13 +275,11 @@ testID={`${FooSelectorsIDs.ITEM}-${item.id}`}
```tsx
import React from 'react';
import {
Box,
ButtonBase,
Text,
TextColor,
TextVariant,
} from '@metamask/design-system-react-native';
import { useTailwind } from '@metamask/design-system-twrnc-preset';
import { strings } from '../../../../locales/i18n'; // adjust depth
import { FooProps } from './Foo.types';
import { FooSelectorsIDs } from './Foo.testIds';
Expand All @@ -271,17 +289,13 @@ const Foo: React.FC<FooProps> = ({
onClose,
testID = FooSelectorsIDs.CONTAINER,
}) => {
const tw = useTailwind();

if (!isVisible) return null;

return (
<ButtonBase
onPress={onClose}
testID={testID}
style={({ pressed }) =>
tw.style('px-4 pb-6', pressed && 'bg-pressed')
}
twClassName={(pressed) => `px-4 pb-6 ${pressed ? 'bg-pressed' : ''}`}
>
<Text
variant={TextVariant.BodyMd}
Expand All @@ -297,7 +311,7 @@ const Foo: React.FC<FooProps> = ({
export default Foo;
```

> For a bottom sheet, add `useElevatedSurface()` — see Section 5.
> For a bottom sheet, use the MMDS `BottomSheet` components — see Section 5.

### `index.ts`

Expand Down Expand Up @@ -385,6 +399,7 @@ Re-exports point at the component's own `index.ts` (`./Foo`), not directly at th
- [ ] `Foo.test.tsx` — colocated (not in `__tests__/`); testIds via constant (never raw strings); `toBeOnTheScreen()` for presence, `.toBeNull()` for absence; `beforeEach(jest.clearAllMocks)`
- [ ] ESLint and TypeScript pass: no `any`, no `eslint-disable`, no import fence violations
- [ ] If consumed outside the folder: parent feature `index.ts` updated (Section 10)
- [ ] If bottom sheet: `useElevatedSurface()` applied; `ScrollView` from `react-native-gesture-handler`
- [ ] If bottom sheet: MMDS `BottomSheet` components, no extra surface class unless the design needs one; `ScrollView` from `react-native-gesture-handler`
- [ ] No new usage of `@deprecated` MMDS APIs; pressed styles via `ButtonBase twClassName={(pressed) => ...}` or `Pressable` + `tw.style()`
- [ ] All user-visible strings use `strings()` — no hardcoded copy

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ parent: content-guidelines

# MetaMask Content Design Guidelines — Mobile

> Source of truth: MetaMask Content Design Style Guide (internal). This skill encodes the decisions from that guide for AI-assisted development. For component-specific copy rules, read the relevant component README in MetaMask/metamask-design-system via Storybook MCP.
> Source of truth: MetaMask Content Design Style Guide (internal). This skill encodes the decisions from that guide for AI-assisted development. For component-specific copy rules, read the "Content guidelines" section of the component README in MetaMask/metamask-design-system on GitHub, at the tag `@metamask/design-system-react-native@<installed version>` (`packages/design-system-react-native/src/components/<Component>/README.md`). No MCP server is needed.

---

Expand Down
7 changes: 5 additions & 2 deletions domains/ui/skills/content-guidelines/skill.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ maturity: stable

Encodes the MetaMask Content Design Style Guide for AI-assisted development.
Covers capitalization, punctuation, voice and tone, and the approved
terminology list. For component-specific copy rules, refer to the relevant
component README in MetaMask/metamask-design-system (exposed via Storybook MCP).
terminology list. For component-specific copy rules, read the "Content
guidelines" section of the relevant component README in
[MetaMask/metamask-design-system](https://github.com/MetaMask/metamask-design-system)
on GitHub, at the tag that matches the installed package version. No MCP
server is needed.

## When to use

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Reading the MMDS components manifests

MMDS publishes a Storybook components manifest for each platform:

| Platform | Manifest |
| --- | --- |
| React (Extension) | <https://metamask.github.io/metamask-design-system/manifests/components.json> |
| React Native (Mobile) | <https://metamask.github.io/metamask-design-system/react-native/manifests/components.json> |

This file explains the format. It deliberately lists no components, versions,
or props: read those from the manifest and the installed package.

## What the manifest is

- It is generated from the Storybook build of MMDS `main`. It can be ahead of
the version a consumer repo installs, so a component or prop in the manifest
may not exist in `node_modules` yet. The installed types decide.
- It is large (around 1 MB). Fetch it once and search it, for example with
`curl -s <url> | jq` or a script, rather than reading it whole.
- It is a discovery and deprecation index, not the API contract.

## Shape

```text
{
"v": <format version>,
"components": {
"<story id>": {
"id": "<story id>",
"name": "<ComponentName>",
"path": "<story file in the MMDS repo>",
"import": "<import line(s) used by the stories>",
"jsDocTags": { "deprecated": ["<reason and replacement>"] },
"reactDocgen": { "description": "...", "props": { "<prop>": { "required": ..., "tsType": ..., "description": "..." } } },
"stories": [ { "id": "...", "name": "...", "snippet": "<example JSX>" } ],
"description": "<optional>",
"error": "<present instead of reactDocgen when docgen failed>"
}
},
"meta": { ... }
}
```

Entries are keyed by Storybook story id, not by component name, and not every
entry is a component:

- Design-token and foundation pages (ids starting `design-tokens-` or `docs-`,
with story paths in `packages/design-tokens`).
- Pattern stories (ids starting `patterns-`). These are composition examples.
Their `name` can look like a component (for example `MarketingMoment`) or
be a code fragment (`() => null`), and nothing with that name is exported.
- Story wrappers whose `name` is a cast expression rather than an identifier.

Treat an entry as a component only when its `path` is a story under the
platform package's `src/components/` (including `temp-components/`) and the
component name appears in the installed export index.

## Common queries

- **Is there a component for X?** Search `name` and `reactDocgen.description`, then confirm
the name is exported by the installed package index.
- **Is it deprecated?** A non-empty `jsDocTags.deprecated` means deprecated;
the message names the replacement. Also check for `@deprecated` in the
installed `.types` file, because the installed version may differ.
- **Which props does it take?** `reactDocgen.props` gives names, types,
`required`, and descriptions for `main`. Confirm each prop in the installed
types before using it.
- **How is it used?** `stories[].snippet` shows example JSX.

## Caveats

- `import` lines come from MMDS story files. They may import enums from
`@metamask/design-system-shared` or use relative paths. In product code,
import components and enums from the platform package
(`@metamask/design-system-react` or `@metamask/design-system-react-native`).
- `jsDocTags` is `{}` when a component has no tags. An entry without a
`deprecated` key is not deprecated in `main`; the installed version can
still differ.
- An entry with `error` and no `reactDocgen` has no prop data. Read the
installed types instead.
- Do not copy manifest content into a skill. It changes with every MMDS merge.
Loading
Loading