Контекст
ds-context
Модель плохо следует дизайн-системе ещё и потому, что ей отдают плохой контекст: простыню доков, половину Storybook и ни одного антипаттерна. ds-context собирает из локальных файлов короткий пакет и показывает, сколько токенов стоит каждая стратегия упаковки.
Зачем
Агент путает систему не только из-за слабой модели. Ему часто отдают либо ничего, либо весь Storybook сразу. В первом случае он рисует свой Button. Во втором тонет в токенах и примерах, которые не относятся к задаче.
ds-context стоит перед моделью. Он собирает контекст, который потом можно отдать Claude или Codex и проверить в ds-eval.
Вход
MVP читает папку. Он не открывает Storybook и не ходит в Figma API. Файл из Figma попадает сюда уже как markdown, например после figma-to-design-md. Фикстура Acme — пять файлов:
fixtures/acme/
tokens.css
components.json
patterns.md
anti-patterns.md
examples.md
dist/
design-system.md
components.md
patterns.md
anti-patterns.md
examples.md
manifest.jsontokens.css — шкала, с которой потом сверяется починка.
:root {
--color-accent: #8B5CF6;
--color-text: #212223;
--color-surface: #ffffff;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--radius-2: 8px;
--font-size-body: 14px;
}components.json — имя, пропсы, пример и чего избегать. Пример попадает в пакет только в стратегии full.
[
{
"name": "Button",
"props": ["variant", "size", "children"],
"example": "<Button variant=\"primary\">Save</Button>",
"avoid": "A raw <button> with an inline background."
},
{
"name": "Input",
"props": ["label", "hint", "error"],
"example": "<Input label=\"Email\" />",
"avoid": "An unlabeled <input>."
},
{
"name": "Dialog",
"props": ["open", "title", "onClose"],
"example": "<Dialog open title=\"Delete account\" />",
"avoid": "A <div className=\"modal\"> with a hand-rolled overlay."
},
{
"name": "Select",
"props": ["label", "options", "value"],
"example": "<Select label=\"Country\" options={countries} />",
"avoid": "A native <select> when the system Select exists."
}
]Три markdown-файла задают паттерны, запреты и короткие примеры экранов.
# Patterns
## Destructive confirm
Ask for confirmation before a delete. Use Dialog, name the object, and make the confirm button the danger variant.
## Empty state
Show one next action. Do not invent a second illustration style.
## Settings
Group fields by task. Use Input with a label. Actions sit in the page footer, not inside the form card.# Anti-patterns
- Do not hardcode #8B5CF6. Use var(--color-accent).
- Do not build a modal from a positioned div.
- Do not add a button with no accessible name.
- Do not pick 13px of padding. Use the space scale.# Examples
A settings page uses Input for the name and email, Select for the country, and Button for save.
A delete flow opens Dialog. The confirm action is variant="danger". The close control has an accessible name.
Empty lists use the empty-state pattern: one sentence and one Button.Запуск
python3 ds-context/ds_context.py build ds-context/fixtures/acmeКоманда пишет пакет в ds-context/fixtures/acme/dist. Это офлайн-сборка: без ключей и без вызова модели. Печать команды на этой фикстуре:
source ds-context/fixtures/acme
out ds-context/fixtures/acme/dist
pack files
design-system.md ~ 292 tokens
components.md ~ 160 tokens
patterns.md ~ 87 tokens
anti-patterns.md ~ 54 tokens
examples.md ~ 72 tokens
strategies (estimate, ~4 chars/token, manifest excluded)
full ~ 665
compact ~ 375
components ~ 180Выход
design-system.md — то, что можно положить в контекст целиком. В стратегии full сюда же встроены паттерны, антипаттерны и примеры. Отдельные файлы в dist/ повторяют исходные markdown.
# Design system
Components: Button, Input, Dialog, Select.
## Tokens
| Token | Value |
| --- | --- |
| `--color-accent` | #8B5CF6 |
| `--color-text` | #212223 |
| `--color-surface` | #ffffff |
| `--space-2` | 8px |
| `--space-3` | 12px |
| `--space-4` | 16px |
| `--radius-2` | 8px |
| `--font-size-body` | 14px |
# Patterns
## Destructive confirm
Ask for confirmation before a delete. Use Dialog, name the object, and make the confirm button the danger variant.
## Empty state
Show one next action. Do not invent a second illustration style.
## Settings
Group fields by task. Use Input with a label. Actions sit in the page footer, not inside the form card.
# Anti-patterns
- Do not hardcode #8B5CF6. Use var(--color-accent).
- Do not build a modal from a positioned div.
- Do not add a button with no accessible name.
- Do not pick 13px of padding. Use the space scale.
# Examples
A settings page uses Input for the name and email, Select for the country, and Button for save.
A delete flow opens Dialog. The confirm action is variant="danger". The close control has an accessible name.
Empty lists use the empty-state pattern: one sentence and one Button.components.md — API. Пример и строка Avoid берутся из JSON.
# Component API
### Button
Props: `variant`, `size`, `children`
Example:
```jsx
<Button variant="primary">Save</Button>
```
Avoid: A raw <button> with an inline background.
### Input
Props: `label`, `hint`, `error`
Example:
```jsx
<Input label="Email" />
```
Avoid: An unlabeled <input>.
### Dialog
Props: `open`, `title`, `onClose`
Example:
```jsx
<Dialog open title="Delete account" />
```
Avoid: A <div className="modal"> with a hand-rolled overlay.
### Select
Props: `label`, `options`, `value`
Example:
```jsx
<Select label="Country" options={countries} />
```
Avoid: A native <select> when the system Select exists.Стратегии
Оценка размера — около 4 символов на токен. Это не токенайзер Claude. Манифест в сумму не входит. На фикстуре Acme:
| Стратегия | Оценка | Что внутри |
|---|---|---|
| full | ~665 | Токены, API с примерами, паттерны, антипаттерны и примеры экранов |
| compact | ~375 | Токены, API без примеров и антипаттерны. Отдельный examples.md не пишется |
| components | ~180 | Только обзор с токенами и API. Паттерны и примеры не пишутся |
Полный пакет по файлам:
| Файл | Оценка |
|---|---|
design-system.md | ~292 |
components.md | ~160 |
patterns.md | ~87 |
anti-patterns.md | ~54 |
examples.md | ~72 |
Манифест
Манифест нужен следующему шагу контура: выбрать стратегию под бюджет токенов и отдать модели только эти файлы. Имена компонентов и токенов лежат списком, чтобы ui-repair и ds-eval сверялись с тем же источником.
{
"strategy": "full",
"source": "ds-context/fixtures/acme",
"components": [
"Button",
"Input",
"Dialog",
"Select"
],
"tokens": [
"--color-accent",
"--color-text",
"--color-surface",
"--space-2",
"--space-3",
"--space-4",
"--radius-2",
"--font-size-body"
],
"files": {
"design-system.md": 292,
"components.md": 160,
"patterns.md": 87,
"anti-patterns.md": 54,
"examples.md": 72
},
"tokens_total": 665
}Куда встаёт
Figma / локальная спека
→ ds-context
→ модель
→ ui-repair
→ ds-eval
→ prompt-regressds-context готовит контекст. ds-eval измеряет, помог ли он. prompt-regress показывает, не сломала ли новая версия промпта то, что уже проходило.
Предел
Инструмент не открывает Storybook и не ходит в Figma. Он не выбирает кусок пакета под один экран: стратегии глобальные. Оценка токенов годится, чтобы сравнить пакеты между собой, и не годится как счёт из API.