Для человека
Правила для ИИ-агента
Чтобы ChatGPT, Cursor или другой ИИ писал материалы в синтаксисе Демонстратора — скачайте пакет правил и отдайте его агенту.
Внутри: как писать блоки, какой блок выбрать, темы, виджеты, типографика. Распакуйте и приложите файлы к агенту — до просьбы «напиши урок».
Как пользоваться
В Cursor / Claude Code / VS Code
- Распакуйте zip в правила проекта (Cursor Skills,
.cursor/rules,AGENTS.md— как принято у вас). - В личном кабинете возьмите API-токен.
- Подключите MCP по конфигу ниже.
{
"mcpServers": {
"demonstrator-mcp": {
"url": "https://app.longread.agency/mcp/demonstrator/mcp",
"headers": {
"Authorization": "Bearer ВСТАВЬ_ТОКЕН_ИЗ_ЛК"
}
}
}
}
/mcp/demonstrator/mcp (не /sse). Без токена подключение не сработает.В ChatGPT / Gemini / NotebookLM
- Загрузите файлы из zip в Knowledge / файлы проекта / вложение чата.
- Попросите написать материал.
- Скопируйте готовый markdown в редактор Демонстратора.
Дополнительно (не обязательно)
Нужны, если готовите исходники из Word/PowerPoint или заливаете медиа с диска через helper-скрипт. Для обычной работы с материалами хватает основного zip.
Что внутри пакета
- Синтаксис блоков
- Какой блок выбрать
- MCP (для Cursor и похожих)
- CSS-темы
- ИИ-HTML
- Русская типографика
Полный текст — во вкладках ниже и в файлах .md. Если правила уже лежат у вас локально — сверьте дату обновления: если на сайте новее, скачайте zip снова.
Для агента и даты файлов
Primary-источник правил — raw .md на этом origin: начни с SKILL.md и README.md, затем 01–06. Вкладки ниже — зеркало. Не меняй план без подтверждения пользователя. Без MCP — отдай готовый markdown, не вызывай API; медиа — CDN-заполнитель или URL от пользователя.
Даты обновления
Сравни updated: в своих копиях с таблицей. Если старше — заново возьми zip или raw .md. Не сравнивай по mtime.
Основной пакет
| Файл | Обновлён |
|---|---|
| README.md | updated: 2026-08-10 14:30 GMT+3 |
| SKILL.md | updated: 2026-08-10 14:30 GMT+3 |
| 01-syntax.md | updated: 2026-08-06 19:20 GMT+3 |
| 02-methodology.md | updated: 2026-08-06 14:19 GMT+3 |
| 03-mcp-tools.md | updated: 2026-08-10 14:30 GMT+3 |
| 04-css-generation.md | updated: 2026-08-06 13:15 GMT+3 |
| 05-html-widget-rules.md | updated: 2026-08-06 23:20 GMT+3 |
| 06-russian-typography.md | updated: 2026-08-06 17:35 GMT+3 |
Помощники (отдельный zip)
| Файл | Обновлён |
|---|---|
| helpers/README.md | updated: 2026-08-07 11:45 GMT+3 |
| helpers/source-cleanup.md | updated: 2026-08-07 11:45 GMT+3 |
| helpers/upload-local-media.ps1 | mtime: 2026-08-07 11:44:35 MSK |
Страница собрана: 2026-08-10 15:19:27 MSK
Справочник правил
Синтаксис Демонстратора
Материал — один Markdown-файл. Интерактив — блоки :::тип … :::/тип.
Жёсткие правила
1. Открытие: :::имя в начале строки. Закрытие: только :::/имя в начале строки. Для каждого открытого блока — своё закрытие. Без исключений. 2. URL и текст тела — со следующей строки после :::имя. На строке :::имя — только имя, вариант и модификаторы. 3. Не выдумывай имена, варианты и модификаторы вне таблицы ниже. 4. %% в начале строки — комментарий. При рендере отбрасывается. 5. GFM-таблицы и автолинки поддерживаются. 6. Блок многострочный: :::имя, пункты ===, тело и :::/имя — отдельные строки. Не склеивай в одну строку (:::steps === … === … :::/steps — запрещено). 7. :::important — короткая врезка (обычно несколько предложений). Не оборачивай в important весь урок, статью или файл с # заголовками и несколькими разделами. 8. Русский текст — по 06-russian-typography.md: тире —, кавычки «ёлочки», многоточие …; не - и не "..." в прозе.
Полная таблица блоков
| Блок | Варианты (после имени) | Модификаторы | Размеры на строке ::: | Закрытие |
|---|---|---|---|---|
acc | — | — | — | :::/acc |
tab / tabs | — | — | — | :::/tab |
flip | — | — | — | :::/flip |
test | — | — | — | :::/test |
steps | grid | — | — | :::/steps |
checklist | duo | — | — | :::/checklist |
compare | — | — | — | :::/compare |
button | group | — | — | :::/button |
important | idea, problem, solution, info, rule | — | — | :::/important |
tmp | video, sim, dialog, hotspot, hint | — | — | :::/tmp |
embed | — | wide | — (размеры в теле) | :::/embed |
audio | — | — | — | :::/audio |
video | — | wide | WxH (напр. 960x540) | :::/video |
file | — | — | — | :::/file |
web_archive | — | wide | WxH | :::/web_archive |
ai_widget | — | wide | WxH | :::/ai_widget |
picfont | chat, right | — | — | :::/picfont |
slider | duo | wide | — | :::/slider |
hotspot | — | wide | — | :::/hotspot |
columns | — | wide | — | :::/columns |
Пиши :::columns … :::/columns.
:::comments — служебный. Не создавай вручную.
Картинка в обычном Markdown — . Не оборачивай в  URL внутри блоков, где синтаксис требует голый URL (:::audio / :::video / :::picfont / аватары в :::picfont chat и т.п.). Исключение: кадры :::slider и фон :::hotspot — там как раз .
Вложенность
- Внутри
:::acc,:::tab,:::flip,:::steps,:::compareразрешён один уровень вложенных блоков:::или картинок. - Внутри пункта
:::hotspotпосле координат — только плоский Markdown. Вложенные:::запрещены. - Не вкладывай блок того же типа в себя (
:::accвнутри:::acc). - Колонки глубже одного уровня не используй.
Заголовки
Только ATX уровней 1–3:
Заголовок H1
Заголовок H2
Заголовок H3
H4–H6 и setext не используй.
Текст
| Назначение | Синтаксис | Запрещено |
|---|---|---|
| Жирный | **текст** или __текст__ | — |
| Курсив | *текст* или _текст_ | — |
| Код | ` код ` | — |
| Ссылка | [текст](URL) | — |
| Картинка |  | [текст](URL) без ! — это ссылка, не картинка |
Списки: - пункт или * пункт; нумерованные 1. 2.. Маркер + в обычном списке не используй (в чеклисте + — отдельный синтаксис).
Цитата: >, >>, >>> в начале строки.
Разделитель: строка из минимум трёх дефисов ---.
Изображение
Канон:
- Текст в
![…]— подпись под картинкой (figcaption). - Пиши осмысленную подпись. Пустые
ипарсер принимает, но для обычных картинок и хотспотов не используй. - HTTPS-URL с любого хоста для markdown-картинок разрешены. Для демо бери CDN ниже. Без MCP: CDN-заполнитель или URL от пользователя.
Важное
Краткая форма (одна строка):
!!! Текст замечания.
Блочная форма:
:::important
Текст замечания.
:::/important
С вариантом:
:::important rule
Не храните пароли в чате.
:::/important
| Вариант | Когда | Что рисует система |
|---|---|---|
| *(без)* | Замечание | Иконка info, серый фон |
idea | Совет | Лампочка, жёлтый фон |
problem | Ошибка | Треугольник, красный фон |
solution | Решение | Галочка, зелёный фон |
info | Справка | Info, синий фон |
rule | Норма / принцип | Параграф §, акцентный фон |
Иконку система добавляет сама. Не вставляй эмодзи и символы иконок в текст блока.
Не используй important как обёртку всего материала. Каркас урока — обычный Markdown (# / ## / абзацы); important — точечный акцент внутри.
Медиа: единый формат тела
| Блок | Строка 1 тела | Строка 2+ | Пример открытия |
|---|---|---|---|
audio | URL | подпись (необязательно) | :::audio |
video | URL | подпись (необязательно) | :::video или :::video wide или :::video 960x540 |
file | URL | имя файла (обязательно для подписи) | :::file |
web_archive | URL | подпись (необязательно) | :::web_archive / wide / WxH |
ai_widget | URL | подпись (необязательно) | :::ai_widget / wide / WxH |
embed | URL === WxH одной строкой | — | :::embed или :::embed wide |
picfont | URL | текст рядом | :::picfont или :::picfont right |
picfont chat | после === Имя — голый URL аватара, затем текст реплики | — | :::picfont chat |
:::audio
https://cdn.longread.agency/demo/audio-sample.mp3
:::/audio
:::video
https://cdn.longread.agency/demo/video-sample.mp4
:::/video
:::file
https://cdn.longread.agency/demo/file-demo.pdf
Раздаточный материал
:::/file
:::web_archive
https://cdn.longread.agency/demo/archive-demo/index.html
:::/web_archive
:::ai_widget
https://cdn.longread.agency/demo/widget-demo.html
:::/ai_widget
Имя блока — ai_widget (не ai-widget). Голый URL HTML в абзаце или «ссылка в чат» не заменяют блок.
ИИ-HTML через MCP: create-widget → save-widget-draft → bake-widget → insert-ai-widget-block (fence = id) → poll archives/ по маркеру. Не сдавай по draft. Без вставки в материал задача не сдана. Правила — 05-html-widget-rules.md. Внешние картинки без расширения файла на CDN блокируются при bake.
:::embed
https://longread.media === 640x360
:::/embed
По умолчанию для embed без размеров в теле — 640×360.
:::picfont
https://cdn.longread.agency/demo/picfont-icon.webp
Короткий факт рядом с картинкой.
:::/picfont
:::picfont chat
=== Ассистент
https://cdn.longread.agency/demo/avatar-bot.webp
Ответ ассистента.
=== Пользователь
https://cdn.longread.agency/demo/avatar-user.webp
Вопрос пользователя.
:::/picfont
В :::picfont chat у каждой реплики:
1. === Имя (имя собеседника) 2. Следующая строка — только голый HTTPS-URL аватара (без !, без […], без подписи) 3. Далее текст сообщения
Нельзя (ломает чат — аватар становится огромной картинкой в пузыре):
=== Новичок

Текст реплики.
Нужно:
=== Новичок
https://cdn.longread.agency/images/….webp
Текст реплики.
При замене локальных путей / CDN-URL внутри :::picfont chat меняй только строку URL. Не превращай её в markdown-картинку .
Обычный :::picfont (не chat): тоже голый URL на первой строке тела, текст — со второй. Не .
Слайдер
:::slider
=== Кадр 1

Текст первого кадра.
=== Кадр 2

Текст второго кадра.
:::/slider
:::slider duo
=== Было

Интерфейс до изменений.
=== Стало

Новый интерфейс.
:::/slider
:::slider wide и :::slider duo wide допустимы.
Интерактивы
Аккордеон
:::acc
=== Заголовок пункта
Содержимое пункта.
=== Второй заголовок
Содержимое второго пункта.
:::/acc
Вкладки
:::tab
=== Вкладка 1
Содержимое первой вкладки.
=== Вкладка 2
Содержимое второй вкладки.
:::/tab
Карточки flip
:::flip
=== Термин
Определение на обороте.
=== Второй термин
Второй ответ.
:::/flip
Допустимо однострочно: лицо === оборот.
Хотспот
:::hotspot

=== 30% 40% Зона A
Пояснение зоны A.
=== 1 70% 55% Зона B
Маркер с цифрой 1.
:::/hotspot
=== 30% 40% Имя— точка.=== 1 70% 55% Имя— маркер с цифрой.- Координаты — проценты от левого верхнего угла.
- Без строк
===блок = обычное изображение.
Кнопка
Кнопки — только внешние ссылки. Не используй их как навигацию по материалу или проекту: у экспорта проекта есть встроенный плеер.
:::button
Подробнее на Longread.Media === https://longread.media
:::/button
:::button group
=== Longread.Media === https://longread.media
=== Ecourse.Studio === https://ecourse.studio
:::/button
Шаги
:::steps
=== Откройте файл
Дважды щёлкните по ярлыку.
=== Сохраните файл
Ctrl+S.
:::/steps
:::steps — столбец со стрелками ↓. :::steps grid — сетка без стрелок.
Чеклист
Маркер в начале строки задаёт тон пункта:
| Маркер | Вид | Когда |
|---|---|---|
+ | Зелёная галочка ✓ | Плюс, возможность, «как надо», факт-преимущество |
- | Красный крест ✗ | Минус, ошибка, «как не надо» |
Список возможностей / фич / преимуществ — только +. Не ставь - «по привычке списка»: - в чеклисте = негатив.
:::checklist
+ Правильный пункт
- Неправильный пункт
Пояснение без маркера
:::/checklist
:::checklist duo
=== + Правильно
Верный подход.
=== - Неправильно
Ошибочный подход.
:::/checklist
Сравнение
Ровно две секции ===:
:::compare
=== Плохо
Неструктурированный текст.
=== Хорошо
Текст с заголовками.
:::/compare
Тест
Открытие — только строка :::test. Режим — следующая строка тела: [test] / [verification] или [think] / [narrative].
| Нельзя | Надо |
|---|---|
:::test[test] | :::test затем строка [test] |
:::test test | то же |
режим на одной строке с ::: | режим внутри тела |
Режим [test] / [verification]: нужен минимум один + и один -.
:::test
[test]
===
Вопрос?
+ Правильный вариант
- Неправильный вариант
ye: Верно!
no: Подумайте ещё.
:::/test
Режим [think] / [narrative]: вариантов с + нет.
:::test
[think]
===
Что вы думаете?
- Вариант 1
- Вариант 2
- Вариант 3
ok: Спасибо за ответ!
:::/test
Строки ye:, no:, ok: необязательны: если их нет, система подставит дефолтный текст. Пиши их явно, когда нужен свой текст обратной связи.
Заглушка
| Открытие | Вид заглушки |
|---|---|
:::tmp | Карточка 2:1, подпись «Заглушка» |
:::tmp video | Подпись «Видео» |
:::tmp sim | Подпись «Симулятор» |
:::tmp dialog | Подпись «Диалог» |
:::tmp hotspot | Подпись «Маркеры» |
:::tmp hint | Текстовая плашка без картинки |
:::tmp
Скоро здесь будет схема
:::/tmp
Колонки
:::columns
70-30
===
Первая колонка.
===
Вторая колонка.
:::/columns
- Первая строка тела — соотношение:
50-50,70-30,2:1,1:1:1. Не50/50. - Разделитель колонок —
===на отдельной строке без текста после===. - Заголовок внутри колонки —
###или**…**, не=== Заголовок. - Широкий ряд:
:::columns wide.
| Нельзя | Надо |
|---|---|
50/50 | 50-50 или 1:1 |
=== Заголовок как разделитель | === пустой; заголовок — ### |
Служебное
Строка <<текст>> — метка задачи. Рендерится как текст в угловых кавычках.
CDN-заполнители
| Блок | URL |
|---|---|
| Изображение | https://cdn.longread.agency/demo/image-demo.webp |
| Хотспот | https://cdn.longread.agency/demo/hotspot-demo.webp |
| Аудио | https://cdn.longread.agency/demo/audio-sample.mp3 |
| Видео | https://cdn.longread.agency/demo/video-sample.mp4 |
| Файл | https://cdn.longread.agency/demo/file-demo.pdf |
| Веб-архив | https://cdn.longread.agency/demo/archive-demo/index.html |
| ИИ-HTML | https://cdn.longread.agency/demo/widget-demo.html |
| Picfont | https://cdn.longread.agency/demo/picfont-icon.webp |
| Аватар бот | https://cdn.longread.agency/demo/avatar-bot.webp |
| Аватар пользователь | https://cdn.longread.agency/demo/avatar-user.webp |
| Слайдер | …/slider-1.webp, slider-2.webp, slider-3.webp |
| Слайдер duo | …/slider-before.webp, …/slider-after.webp |
| Обложка проекта | https://cdn.longread.agency/demo/project-cover.webp |
Методика: какой блок выбрать
Используйте эту таблицу для выбора блока под задачу.
Быстрый выбор
| Задача | Блок |
|---|---|
| FAQ, глоссарий, однородные пункты «заголовок → текст» | :::acc |
| Равнозначные панели, сценарии | :::tab |
| Термин ↔ определение, самопроверка | :::flip |
| Проверка знаний | :::test |
| Процесс с порядком, инструкция | :::steps |
| Критерии, плюсы/минусы, «как надо» | :::checklist |
| Контраст «плохо ↔ хорошо» | :::compare |
| Важная оговорка, идея, правило | !!! или :::important |
| Кликабельные точки на схеме | :::hotspot |
| Две–три колонки вёрстки | :::columns |
Когда что использовать
Аккордеон (:::acc)
Используйте для однородных пунктов: заголовок открывает пояснение по клику.
Подходит для:
- Глоссария: термин — заголовок, определение — тело.
- FAQ: вопрос — заголовок, ответ — тело.
- Подсказок к шагам, когда порядок не важен.
Не путайте с :::steps. Аккордеон не нумерует пункты.
Вкладки (:::tab)
Используйте для равнозначных панелей с короткими ярлыками.
Подходит для:
- Вариантов: теория / практика, условие / решение.
- «До и после» без морали «плохо/хорошо».
Не используйте вкладки для контраста «плохо/хорошо». Для этого — :::compare или :::checklist duo.
Карточки (:::flip)
Используйте для самопроверки: вспомнил → перевернул → проверил.
Лицо — тезис. Оборот — развёрнутый ответ.
Глоссарий из 10+ терминов лучше делать аккордеоном.
Тест (:::test)
[test]/[verification]— один правильный ответ. Обязателен минимум один+и один-.[think]/[narrative]— опрос. Нет правильного ответа. Нейтральныйok:.
Не ставьте [test] с искусственным + там, где подходит [think].
Шаги (:::steps)
Используйте для процесса с порядком: инструкция, алгоритм, «сначала → потом».
:::steps— со стрелками между шагами.:::steps grid— сетка без стрелок.
Не используйте :::steps для норм без последовательности. Для этого — :::important rule или чеклист.
Чеклист (:::checklist)
Используйте для критериев, требований, списка «что проверить» или списка возможностей.
+в начале строки — зелёная галочка (плюс / фича / «как надо»).-в начале строки — красный крест (минус / ошибка).- Список преимуществ или возможностей продукта — все пункты с
+. Не используйте-как обычный маркер списка. - Одна колонка:
:::checklist. - Две колонки:
:::checklist duo. Тональность:=== + …/=== - ….
Отличие от :::compare: чеклист — набор пунктов с ✓/✗. Сравнение — ровно 2 текстовые колонки.
Тест (:::test)
- Открытие только
:::test. Режим[test]или[think]— отдельной строкой внутри блока. - Не пишите
:::test[test]и не клеите режим к имени блока.
Сравнение (:::compare)
Используйте для контраста подходов. Ровно 2 колонки с заголовками.
Важное (:::important)
- Краткая оговорка:
!!! текст. - Блок:
:::important idea/problem/solution/info/rule. - Иконку система рисует сама. Не вставляйте эмодзи и символы иконок в текст.
- Только короткая врезка. Не оборачивайте весь урок или статью в
:::important.
Хотспот (:::hotspot)
Используйте для схемы или фото с кликабельными точками.
Требуется реальная картинка . Без маркеров блок ведёт себя как обычное изображение.
Колонки (:::columns)
Используйте для параллельной вёрстки: текст + врезка, две равные колонки.
Пишите :::columns … :::/columns.
Соотношение: пресет (2:1, 1:1:1) или проценты через дефис (70-30). Не 50/50. Разделитель — пустой ===. Заголовки внутри — ###.
Не заменяйте колонками :::compare или :::checklist duo. В колонках нет семантики «плохо/хорошо».
Не путать
| Хотели | Не ставьте | Ставьте |
|---|---|---|
| Последовательность шагов | :::acc с «Шаг 1» в заголовках | :::steps |
| Норма / принцип | :::steps | :::important rule |
| Контраст «плохо / хорошо» | Две вкладки | :::compare |
| Много пунктов ✓/✗ | :::compare | :::checklist или :::checklist duo |
| Глоссарий 10+ терминов | Пачка :::flip | :::acc |
| Опрос без верного ответа | [test] с искусственным + | [think] |
| Две колонки | 50/50 в первой строке | 50-50 или 1:1 |
Anti-patterns: wrong → right
Шаги как аккордеон — нельзя
Так нельзя:
:::acc
=== Шаг 1
Откройте файл.
=== Шаг 2
Сохраните файл.
:::/acc
Так надо:
:::steps
=== Откройте файл
Дважды щёлкните по ярлыку.
=== Сохраните файл
Ctrl+S или меню «Файл».
:::/steps
Норма как steps — нельзя
Так нельзя:
:::steps
=== Правило 1
Не храните пароли в чате.
:::/steps
Так надо:
:::important rule
Не храните пароли в чате.
:::/important
Плохо/хорошо вкладками — нельзя
Так нельзя:
:::tab
=== Плохо
Длинный абзац без структуры.
=== Хорошо
Список и заголовки.
:::/tab
Так надо:
:::compare
=== Плохо
Длинный абзац без структуры.
=== Хорошо
Список и заголовки.
:::/compare
Колонки со слэшем — нельзя
Так нельзя:
:::columns
50/50
===
Левая.
===
Правая.
:::/columns
Так надо:
:::columns
50-50
===
Левая.
===
Правая.
:::/columns
Опрос с фейковым «верным» — нельзя
Так нельзя:
:::test
[test]
===
Как вам курс?
+ Отлично
- Нормально
ye: Верно!
no: Неверно.
:::/test
Так надо:
:::test
[think]
===
Как вам курс?
- Отлично
- Нормально
- Сложно
ok: Спасибо за ответ!
:::/test
Режим теста на строке открытия — нельзя
Так нельзя:
:::test[test]
===
Вопрос?
+ Да
- Нет
:::/test
Так надо:
:::test
[test]
===
Вопрос?
+ Да
- Нет
:::/test
Фичи чеклистом с минусами — нельзя
Так нельзя (все пункты красные ✗):
:::checklist
- Поддерживает мультимодальные запросы
- Использует Query Fan-Out
:::/checklist
Так надо (зелёные ✓):
:::checklist
+ Поддерживает мультимодальные запросы
+ Использует Query Fan-Out
:::/checklist
Весь урок в important — нельзя
Так нельзя: открыть :::important idea в начале файла и закрыть :::/important в конце, а внутри — #, ##, steps, compare.
Так надо: обычный Markdown-каркас; :::important только на короткий акцент (несколько предложений).
Блок в одну строку — нельзя
Так нельзя:
:::steps === Шаг 1 Текст. === Шаг 2 Текст. :::/steps
Так надо:
:::steps
=== Шаг 1
Текст.
=== Шаг 2
Текст.
:::/steps
То же для :::compare и :::checklist duo.
Размещение и объём
- Перед интерактивом добавьте короткую подводку — связующий текст.
- Между блоками — связный текст. Не ставьте несколько интерактивов подряд без пояснений.
- Внутри
:::acc,:::tab,:::flipне ставьте заголовки###. Структура — только через===и текст. - В подводках не используйте штампы: «далее», «ниже», «удобно».
Не выдумывайте несуществующих типов блоков. Используйте только идентификаторы из допустимого списка.
MCP-инструменты Демонстратора
Карта инструментов (имя → зачем). Полные схемы параметров не дублируются здесь.
Параметры инструментов
После подключения MCP клиент вызывает tools/list. Сервер отдаёт канонические inputSchema (required, типы, enums, лимиты).
- Бери аргументы только из
tools/list/ подсказок клиента — не из этой страницы и не из догадок. - Этот файл — ориентир «какой tool выбрать». Контракт вызова — у MCP.
- Без токена схемы недоступны (
401). - Нет нужного tool в
tools/list→ стоп, спроси пользователя. Не обходи дырку delete+create / массовой перезаписью. - Soft-delete в корзину, перенос, смешивание материалов,
replace_allповерх живого контента — только после описания процедуры и прямого подтверждения пользователя (см.README.md, блок СТОП). - Вне MCP (не ищи в
tools/list): permanentdelete-project/delete-resource, снятие share-ссылок, invite/ACL пространства, suggestions propose/apply (WIP), restore из entity-snapshot / backup ZIP.
Подключение к MCP
Подпишись на remote MCP-шлюз на сервере Демонстратора. Клонировать репозиторий и запускать node локально не нужно.
Токен — в Личном кабинете Демонстратора (раздел MCP / API-токен).
{
"mcpServers": {
"demonstrator-mcp": {
"url": "https://app.longread.agency/mcp/demonstrator/mcp",
"headers": {
"Authorization": "Bearer ВСТАВЬ_ТОКЕН_ИЗ_ЛК"
}
}
}
}
Эндпоинты шлюза:
| Метод | URL | Назначение |
|---|---|---|
GET | https://app.longread.agency/mcp/demonstrator/health | Проверка живости |
GET | https://app.longread.agency/mcp/demonstrator/sse | SSE (keepalive; Cursor сюда url не ставь) |
POST | https://app.longread.agency/mcp/demonstrator/mcp | JSON-RPC / streamable HTTP — это URL для IDE |
- В конфиге Cursor / Claude Code в поле
urlуказывай…/mcp, не…/sse. - Заголовок
Authorization: Bearer <токен>обязателен наPOST /mcp. - Без токена —
401. - Токен привязан к аккаунту: права и квоты — как в UI Демонстратора.
- Публичный MCP — только Prod (
app.longread.agency). Не используйdev.app.longread.agencyв публичных правилах/agent/.
Happy path: материал с нуля
1. list-projects → project_id (или create-project). 2. create-material — title + project_id. 3. Markdown по 01-syntax.md / 02-methodology.md. 4. Запись тела — только через Yjs collab-мост, не прямым PATCH в БД:
- полное тело:
apply-material-point-patchсmode: "replace_all"+content
или save-material-content (тот же POST /api/collab/materials/:id/patch);
- точечно:
find_replace_once/range_patch; - title вместе с телом:
save-material-content+title; theme —apply-material-theme.
5. Проверить verify.ok / get-material. В ответе смотри source: yjs_room (комната открыта) или db_fallback.
Запрещено писать markdown через raw PATCH /api/materials с полем content (tool update-material-content удалён): открытый редактор перезапишет старым Yjs-документом.
Полный маршрут и сценарий без MCP — в README.md.
Каталог (обзор)
Ниже — имя и краткое действие. Схемы полей — в tools/list.
Проекты и пространства
| Инструмент | Действие |
|---|---|
list-projects | Получить список проектов |
create-project | Создать проект |
update-project | Обновить проект |
list-spaces | Получить список пространств |
get-space | Получить пространство |
update-space | Переименовать пространство |
list-space-members | Список участников (только чтение) |
Создание пространства, приглашения, смена состава/ролей, permanent delete-project — только через UI, не через MCP.
Структура
| Инструмент | Действие |
|---|---|
list-sections | Список разделов (с sort_order, среди разделов) |
create-section | Создать раздел |
update-section | Обновить раздел (в т.ч. одиночный sort_order) |
reorder-sections | Порядок только среди разделов (sort_order) |
delete-section | Удалить раздел (soft delete) |
list-materials | Список материалов (с sort_order) |
search-materials | Полнотекстовый поиск по материалам |
create-material | Создать материал |
duplicate-material | Клонировать материал (суффикс «(копия)») |
update-material-placement | Переместить материал / один sort_order |
reorder-materials | Порядок уроков внутри раздела (или среди корневых) |
get-project-sequence | Смешанный порядок карточек проекта: раздел ↔ корневой прототип |
patch-project-sequence | Задать смешанный порядок (как DnD в ЛК) |
delete-material | Удалить материал (soft delete) |
Порядок: три разных оси (не путать)
| Что меняешь | Tool | Где видно |
|---|---|---|
| Раздел ↔ корневой прототип вперемешку | get-project-sequence / patch-project-sequence | сетка карточек проекта в ЛК |
| Порядок разделов между собой | reorder-sections (sort_order) | среди разделов |
| Порядок уроков внутри раздела | reorder-materials + section_id | внутри раздела |
Можно чередовать: раздел → прототип → раздел → прототип. Это штатный project_sequence, не запрет продукта.
Стартовый/пустой sequence (миграция + UI-fallback) часто выглядит как «сначала все разделы, потом корневые» — дефолт, не закон. Не сочиняй «разделы всегда сверху» / «без разделов только плоский список».
Дерево слева sequence почти не отражает: смешанный список — в сетке карточек.
patch-project-sequence: items: [{ "item_type": "section"|"material", "item_id": N }, …] сверху вниз. В items только корневые материалы (без section_id). Перед вызовом — подтверждение пользователя (см. СТОП в README.md).
reorder-sections / reorder-materials не умеют смешивать типы — для этого только sequence.
Медиа
| Инструмент | Действие |
|---|---|
list-resources | Список ресурсов (фильтр: projectid, materialid, q) |
presign-media-upload | Init upload audio/video/file/web_archive → resource_id + upload_url (PUT с машины клиента) |
complete-media-upload | Complete после PUT → id, status, full_url (CDN), markdown_snippet |
upload-media-from-fs | Загрузка по file_url (HTTPS) или file_path уже на сервере MCP — не Windows-path клиента |
get-resource-status | Статус обработки медиа (poll до ready / failed) |
insert-media-block | Вставить медиа-блок; display_name / name → имя в медиатеке |
rename-resource | Переименовать ресурс |
Permanent удаление ресурса — только UI (delete-resource в MCP нет).
Upload и insert: осмысленный filename / display_name. «Без названия» в медиатеке — брак; сразу rename-resource.
Как загрузить локальный файл → Object Storage → CDN
MCP не читает файлы с диска агента (C:\…). Не вызывай upload-media-from-fs с Windows-path. insert-media-block файл не загружает. Сначала upload, потом insert.
Запрещено
- Писать свой upload (Python, Node).
- Искать
upload-local-media.ps1вне текущего workspace. - Спрашивать пользователя «как залить».
- Класть файлы на VPS «под from-fs».
- Передавать
file_base64в MCP. - Заливать файл с кириллицей в пути или имени (сначала скопируй в ASCII-имя).
#### Выбор пути
| Что на диске агента | Как |
|---|---|
Картинка (image) | Shell curl multipart (ниже) |
| audio / video / file / web_archive | MCP presign-media-upload → Shell PUT → MCP complete-media-upload |
| Уже HTTPS URL | MCP upload-media-from-fs с file_url + material_id/project_id |
После upload вызови MCP insert-media-block или вставь  в content. Processing-медиа: get-resource-status до ready / failed. На каждом upload передай material_id или project_id.
ASCII-only на диске. Путь и имя файла для upload — только латиница/цифры (C:\work\media\fig-01.png). Кириллица в папках или имени файла ломает curl у агентов. Русское имя в медиатеке — после upload: rename-resource или display_name / name в insert-media-block.
#### Картинка — curl
Токен — из ЛК (тот же Bearer, что у MCP). Prod API: https://app.longread.agency.
curl.exe -sS -X POST "https://app.longread.agency/api/resources" `
-H "Authorization: Bearer TOKEN_FROM_LK" `
-H "Accept: application/json" `
-F "file=@C:\work\media\fig-01.png;filename=fig-01.png;type=image/png" `
-F "material_id=123" `
-F "original_name=fig-01.png"
1. Из JSON возьми id и full_url (или url). 2. Вызови insert-media-block или вставь . 3. Задай читаемое имя. Иначе вызови rename-resource.
Для image нет presign-media-upload. Нет MCP-tool, который читает локальный png. Если upload-local-media.ps1 уже лежит в текущем workspace — можно вызвать его вместо curl. Иначе делай curl. Не сканируй диск.
#### audio / video / file / web_archive
1. MCP presign-media-upload (kind, filename, size, material_id или project_id). 2. Shell: curl.exe -sS -X PUT "<upload_url>" -H "Content-Type: …" --data-binary "@C:\path\to\file". 3. MCP complete-media-upload (тот же material_id / project_id). 4. MCP insert-media-block.
#### Уже публичный HTTPS
MCP upload-media-from-fs: только file_url (https://…). Не C:\….
Медиатека проекта
Медиатека = resource_links на project_id / material_id.
- Upload без
material_id/project_id— MCP отклоняет вызов. - При записи content через collab backend линкует твои ресурсы из markdown в материал/проект.
- Чужой CDN URL / demo-заполнитель без upload в медиатеку не попадает.
Что не делать
- Не писать свои upload-скрипты сверх
curl/ MCP выше. - Не искать helper вне текущего workspace.
- Не считать
insert-media-blockзаменой upload. - Не вызывать несуществующие base64-tools (
upload-media-resource/upload-resource). - Не класть медиа на диск VPS «под from-fs».
- Не подставлять Windows-path в
upload-media-from-fs. - Не загружать без
material_id/project_id.
ИИ-HTML (:::ai_widget)
| Инструмент | Действие |
|---|---|
create-widget | Создать черновик ИИ-HTML. Обязательно name (или caption / original_name) — имя в медиатеке |
get-widget | Получить ИИ-HTML; у linear_dialog — ещё archetype + scenario |
save-widget-draft | Сохранить HTML в черновик (свободная вёрстка). Не для правок линейного диалога |
assemble-linear-dialog | Собрать или обновить линейный диалог из полного scenario JSON (без Studio AI). Фича ai_widget_templates (тестеры) |
bake-widget | Собрать ИИ-HTML в готовый архив |
fork-widget | Форкнуть ИИ-HTML в другой материал |
insert-ai-widget-block | Вставить :::ai_widget в материал |
Имя в медиатеке
Ресурс без нормального original_name в UI выглядит как «Без названия» / бессмысленный дефолт. Это брак.
create-widget: всегда передайname(коротко по смыслу: «Квиз онбординг», не uuid).- Upload: осмысленный
filename; если в библиотеке плохое имя — сразуrename-resource. insert-media-block: можноdisplay_name/name— MCP переименует ресурс.
Не готово: виджет/файл в медиатеке без читаемого имени.
Путь создания ИИ-HTML (только IDE + MCP)
локальный .html + маркер + отладка → вопрос «bake на CDN?» → «да» →
create-widget → save-widget-draft → bake-widget (ready) →
insert-ai-widget-block (fence = id, не draft) →
poll archives/ до совпадения маркера → get-material
1. Запиши и отладь HTML в workspace (widgets/<slug>.html). Добавь уникальный маркер. 2. Спроси пользователя про bake/insert. Жди прямого «да». Не вызывай bake-widget на каждой правке. 3. create-widget → save-widget-draft (HTML с диска) → bake-widget. 4. insert-ai-widget-block — в блок только CDN entry_url после bake (ready). Draft URL и bare id в материал запрещены. 5. Poll: get-resource-status / archive-info → HTML с archives/ (entry_url, учти ?v=). Маркер должен совпасть с локальным файлом. get-widget и draft — не критерий сдачи. 6. get-material — fence на месте. Путь к локальному файлу — пользователю.
В create-widget всегда передай name (имя в медиатеке). Без имени — не готово; при ошибке — rename-resource.
Шаблон: линейный диалог (assemble-linear-dialog)
Когда нужен диалоговый плеер, не пиши HTML с нуля — собери сценарий JSON и вызови assemble-linear-dialog. Shell канонический; агент заполняет данные (пул портретов, локации, реплики с парой слотов).
scenario.json на диске → create-widget → assemble-linear-dialog →
вопрос «bake на CDN?» → «да» → bake-widget → insert-ai-widget-block (CDN URL)
1. Сохрани scenario локально (widgets/<slug>-scenario.json). Поля: characters[] (пул портретов), steps[] с leftPortraitId / rightPortraitId / speakerSide, опционально locations[]. Эталон: docs/templates/linear-dialog/scenario.example.json. 2. На сцене всегда два слота картинок; characters[] — N вариаций (ракурсы/эмоции). На каждой реплике задай пару портретов и кто говорит (speakerSide: left|right). 3. Демо-медиа CDN: avatar-bot.webp, avatar-user.webp, slider-1.webp на cdn.longread.agency/demo/. 4. create-widget с name → assemble-linear-dialog (widget_id + scenario). Не нужен save-widget-draft. 5. Bake/insert — только после прямого «да» (как у свободного HTML). Insert пишет CDN entry_url, не id. 6. При 403 ai_widget_templates_forbidden — шаблоны только у тестеров; не обходи через свободный HTML без согласования.
Правка существующего линейного диалога
Тот же assemble-linear-dialog — создаёт и обновляет. Отдельного «refine» в MCP нет (Studio AI через MCP не вызываем).
get-widget → взять scenario → править JSON (локально или в ответе) →
assemble-linear-dialog (полный scenario) → при необходимости снова bake после «да»
1. get-widget (widget_id) → поля archetype: linear_dialog и scenario. 2. Если scenario пуст — вытащи из HTML #vn-scenario или восстанови из локального widgets/<slug>-scenario.json. 3. Внеси правки в полный scenario (реплики, портреты пула, leftPortraitId/rightPortraitId/speakerSide, локации, порядок steps / next). Не отправляй diff / SEARCH-REPLACE по shell. 4. Обнови локальный widgets/<slug>-scenario.json. 5. assemble-linear-dialog с тем же widget_id и полным scenario — пересоберёт draft. 6. Запрещено для диалога: save-widget-draft с ручным HTML плеера; правка CSS/JS shell; вызов /api/ai/widgets/*/refine*. 7. Повторный bake-widget / insert — только после прямого «да» пользователя (как при создании).
Чат-боты без MCP этот путь не используют. Они отдают HTML/markdown кодом и bake не делают.
Не готово (IDE): только bare id в fence; bake без «да»; bake без локального файла; bake без insert; сдача по draft при отстающем archive; fence с draft_url; ресурс в медиатеке без читаемого имени.
Серверный контракт — 05-html-widget-rules.md.
Корзина
| Инструмент | Действие |
|---|---|
list-project-trash | Список удалённого |
restore-project-trash | Восстановить (items: [{type, id}] или all: true) |
Share-ссылки
Создание и обновление — да. Снятие / unpublish ссылок через MCP нельзя (только UI).
| Инструмент | Действие |
|---|---|
get-material-share-links | Ссылки материала |
create-material-share-link | Создать ссылку материала |
update-material-share-link | Обновить уже созданную ссылку материала (auto_update) |
get-project-share-links | Ссылки проекта |
create-project-share-link | Создать или обновить (refresh_only: true — без ротации токенов) |
get-section-share-links | Ссылки раздела |
create-section-share-link | Создать или обновить (refresh_only) |
republish-comments-snapshot | Обновить HTML-snapshot для публичной ссылки с правками. Не пишет тело урока (content) |
Ответ create/get содержит url — полный канонический URL.
Типы ссылок: preview (просмотр), preview_comments (с комментариями).
Comment/share ≠ editor body. republish-comments-snapshot, share-links с preview_comments и get-material-preview-with-comments — про публичный review/HTML. Текст урока в редакторе правят только save-material-content / apply-material-point-patch. В ответах материала нет внутренних publish-кэшей — только content.
Чтение и экспорт
| Инструмент | Действие |
|---|---|
get-material | id, title, content, theme, version, placement (whitelist) |
get-material-export-data | Markdown + тема материала |
get-section-export-data | Раздел + все материалы с контентом |
get-project-export-data | Дерево проекта для HTML-ZIP |
get-material-preview-with-comments | Read-only HTML snapshot+overlay; не источник для правки markdown |
Предложения правок
Сейчас вне MCP (недоделано; вернём позже). Пиши тело сразу через collab (save-material-content / apply-material-point-patch).
Запись контента
Источник правды при открытом редакторе — Yjs collab, не строка в БД. Все правки тела материала — через collab-мост.
| Инструмент | Действие |
|---|---|
apply-material-point-patch | Канон. replace_all / range_patch / find_replace_once → /api/collab/materials/:id/patch |
save-material-content | Полная замена тела тем же collab-мостом (replace_all) + опционально title/theme. По умолчанию verify_readback: true |
apply-material-theme | Тема (palette / contentStyle / customOverlayCss) |
Режимы apply-material-point-patch
| Режим | Когда использовать |
|---|---|
replace_all | Замена всего контента (основной путь «записать материал») |
range_patch | Правка по смещению: operations: [{ start, delete_count, insert_text }] |
find_replace_once | Замена по тексту: find_text + replace_text. Самый надёжный для кириллицы |
Все write-операции используют expected_version (tool подставит сам, если не передан).
Ответ содержит source:
yjs_room— материал был открыт в редакторе; текст ушёл в Yjs, потом в БД;db_fallback— вкладка редактора не была открыта (нет живых WS).
Если материал открыт в редакторе, а запись в Yjs невозможна, API вернёт 409 (editor_open_room_not_ready / collab_room_push_failed). Не считай это успехом. Закрой вкладку или повтори, когда комната готова. Тихого db_fallback при открытом редакторе больше нет — иначе открытая вкладка затрёт правки агента.
После записи проверяйте verify.ok и source. Не пишите тело через raw PATCH «в базу». Вторичных «workspace»/publish body-полей в ответах нет — править нечего, кроме content через collab.
Темы
| Инструмент | Действие |
|---|---|
list-themes | Список пресетов: minimalism, draft, journal, neon, airy, modern |
apply-material-theme | Применить тему. Поддерживает contentStyle: "custom" + customOverlayCss |
inherit-project-themes | Сбросить темы разделов/уроков проекта на наследование от темы проекта |
Правила CSS для customOverlayCss — см. раздел «Правила CSS-генерации».
Правила CSS-генерации тем
Вы пишете CSS для apply-material-theme с параметром customOverlayCss. Этот CSS изменяет внешний вид материала. Соблюдайте правила ниже.
CSS-переменные
Материалу гарантированно доступны переменные в :root. Используйте их для цветов. Не хардкодьте цвета.
| Переменная | По умолчанию | Назначение |
|---|---|---|
--longread-bg | #f8f8f8 | Фон страницы |
--longread-text | #222 | Цвет текста |
--longread-surface | #fff | Фон карточек |
--longread-surface-text | #222 | Текст на карточках |
--longread-headings | #222 | Цвет заголовков |
--longread-accent | #1f3249 | Акцентный цвет |
--longread-accent-pale | #e0e0e0 | Бледный акцент |
--longread-border | var(--longread-accent-pale) | Цвет границ |
--longread-positive | #20a020 | Зелёный (хорошо) |
--longread-negative | #d04040 | Красный (плохо) |
--longread-important-bg | #f5f5f5 | Фон блока important |
--longread-content-padding | 1.5em 1.25em | Отступ контента |
--longread-block-padding | 1em 1.25em | Отступ внутри блоков |
--longread-block-margin | 1.65em | Отступ между блоками |
Селекторный контекст
Каждое правило начинайте с .longread-theme-custom.
Запрещены селекторы: body, html, :root.
/* Верно */
.longread-theme-custom h1 { color: var(--longread-accent); }
/* Запрещено */
body { background: #fff; }
Опасные CSS-свойства
Эти свойства могут сломать вёрстку блоков Демонстратора:
display, position, flex, grid, width, height, overflow.
Если задача требует одного из этих свойств — сначала предупреди пользователя: объясни, что свойство может поломать вёрстку. Меняй только после прямого подтверждения пользователя.
Безопасные CSS-свойства
По умолчанию используй эти свойства — они не ломают вёрстку:
border, border-radius, border-color, background, font-family, font-size, font-weight, color, text-shadow, box-shadow, padding, margin, transform, letter-spacing.
Псевдоэлементы ::before и ::after разрешены везде, кроме селекторов ниже.
Селекторы с высоким риском
Эти селекторы управляют критичной вёрсткой блоков. Если задача требует их стилизации — сначала предупреди пользователя, что возможна поломка. Меняй только после прямого подтверждения.
.test-optionsиinput[type=radio]/input[type=checkbox]::before,::after,::markerна элементах.test-options
Селекторы с ограничениями
.block.important
- Сохраняйте
padding-left >= 3em. Это место под иконку. - Запрещено менять
::before(position, left, top, transform, display, width, height).
.flip-front и .flip-back
- Сохраняйте
padding-bottom.
blockquote
Три уровня цитат. Используйте эти селекторы.
Уровень 1:
.longread-theme-custom > blockquote:not(:has(blockquote)),
.longread-theme-custom :not(blockquote) > blockquote:not(:has(blockquote)) {
/* стили уровня 1 */
}
Контейнер цитаты (сброс):
.longread-theme-custom blockquote:has(> blockquote) {
border: none;
background: none;
box-shadow: none;
padding-left: 0;
}
Уровень 2:
.longread-theme-custom blockquote:not(:has(> blockquote > blockquote)) > blockquote:not(:has(blockquote)) {
/* только color, font-style, font-size */
/* без border, без ::before */
}
Уровень 3:
.longread-theme-custom blockquote blockquote blockquote {
/* border, border-radius, background, padding */
/* ::before { content: none } */
}