Install
openclaw skills install @sergeypetrakov/dossierДосье на конкретного живого человека перед деловой встречей или переговорами: поиск волнами по открытым источникам, порог подтверждения по силе источника, машинная проверка каждого числа, триангуляция фактов через Perplexity Sonar и детерминированная вёрстка в Word (Arial 12, две страницы) плюс тот же текст в чате.
openclaw skills install @sergeypetrakov/dossierПортрет живого человека перед встречей: кто он/она, как думает, о чём с ним/ней говорить и чего не касаться.
Навык самодостаточный: методика сбора — в этом файле, а проверка фактов и
вёрстка — в его собственных скриптах (scripts/verify_facts.py,
scripts/render_dossier.py). Отдельно ставить ничего не нужно.
Что нужно для работы:
search.py (Perplexity Sonar); browse_page у агента — для
адресного чтения страниц;PERPLEXITY_API_KEY в настройках и доступ к нему в карточке навыка — на нём
работают и поиск (search.py), и проверка (verify_facts.py);python3 и библиотека python-docx — объявлена зависимостью навыка, платформа
ставит её сама в изолированное окружение навыка при установке.Хорошие результаты получены на Sonnet 4.6 и GLM-5.2.
Досье собирается в одном виде, без вариантов: файл Word на две страницы плюс тот же текст в чате (тем же объёмом, не пересказом).
1. Порог подтверждения зависит от силы источника — с отдельной категорией «первое лицо».
| Категория | Что это | Нужно независимых |
|---|---|---|
| Первое лицо | LinkedIn / персональный сайт человека, его интервью, авторская колонка, публичное выступление, его пост | 1 (сам источник) + пометка «со слов X», если факт нельзя проверить извне |
| Сильный | официальный сайт компании, раскрытие информации, годовой отчёт, судебный документ, реестр, деловая пресса первого эшелона со ссылкой на первоисточник | 2 независимых |
| Средний и слабый | деловая пресса без ссылки на первоисточник, отраслевые издания, биографические справочники, агрегаторы, соцсети не самого человека, «топ-10 богатейших», статья без автора | 3 независимых |
Независимые — не перепечатки друг друга: две газеты с одним пресс-релизом считаются за один источник. Три агрегатора одной справки — тоже один.
Почему первое лицо — отдельная категория: карьерные факты (где работал, что окончил, в каком году) человек сам знает точнее любого стороннего источника. Заставлять искать «второе подтверждение» для года окончания вуза, названного самим человеком в LinkedIn, — искусственный дефицит. Но для утверждений о его достижениях, влиянии, роли в сделках — нужен внешний сильный источник, потому что самопрезентация субъективна.
Если набрать нужное число не удалось — факт идёт в «Не подтверждено».
Всегда проверяйте, есть ли у человека страница в LinkedIn с карьерным треком: как правило, это самый точный источник по хронологии работы.
2. Неподтверждённое помечается, а не выбрасывается и не выдаётся за факт. Сведение без подтверждения идёт в раздел «Не подтверждено» с указанием, откуда взято и чего не хватает. Никогда не пишите догадку тоном факта.
3. Факт подаётся как есть. Анализ помечается как анализ.
**[Анализ]** отдельным блоком, а не в фактической фразе.Смешивать нельзя даже в одном предложении. «Опытный переговорщик, с 2019 года возглавляющий M&A-направление [3]» — это анализ («опытный переговорщик»), склеенный с фактом. Разделяйте.
4. Никаких выводов о личности из воздуха. «Судя по фотографиям, он человек закрытый» — выдумка. Черта характера попадает в досье, только если следует из наблюдаемого: слов, решений, свидетельств тех, кто работал. И даже тогда это анализ, а не факт.
5. Ни одного числа, которого нет в источнике дословно.
Это правило появилось из конкретного провала. Досье утверждало: «аналитика для 1 млн+ частных инвесторов [1]». Источник [1] — анкета человека в отраслевом реестре, заполненная им самим, — говорит про частных инвесторов, но никакого числа не содержит. Сплошной поиск по всей доказательной базе прогона, 194 333 знака, дал ноль совпадений «число + инвестор». К верному утверждению был дописан порядок величины, а ссылка осталась прежней — и теперь подпирала то, чего в ней нет.
Опаснее всего то, что число выглядело правдоподобно: у крупных инвестиционных сервисов действительно миллионы пользователей, поэтому на глаз ошибку не поймать ни владельцу, ни собеседнику на встрече.
Поэтому:
figures — с дословной цитатой
источника или с пометкой о выводе. Это проверяет скрипт вёрстки и
отказывается собирать документ, пока подтверждения нет.Анализ и синтез галлюцинацией не считаются и запрещены не они — но они
обязаны стоять отдельно, под пометкой **[Анализ]**, и не притворяться
прочитанным фактом.
Не собираем: домашний адрес, личные телефоны и почту, данные членов семьи (кроме публичной роли в бизнесе), состояние здоровья, ориентацию, сведения о детях, содержание частной переписки, всё, что получено не из открытых источников.
Собираем осторожно, только если это влияет на деловой разговор: судимости и судебные споры — со ссылкой на документ, а не на слух; санкции — с юрисдикцией и датой; политические взгляды — только публично заявленные.
По умолчанию читатель досье — руководитель компании из финансовой и технологической отрасли. Ищите точки пересечения биографии человека с финансами, технологиями и искусственным интеллектом, цифровыми сервисами: от этого зависит выбор тем на обсуждение.
Если владелец в запросе назвал другой контекст (свою роль, компанию, цель встречи), он важнее умолчания.
Тёзки — главный источник ошибок. Закрепите человека минимум двумя признаками: компания и должность, страна, год рождения, написание имени на родном языке.
Имена с Ближнего Востока и из Азии переводятся по-разному: Си Цзиньпин / Xi Jinping, Мухаммед бин Салман / MBS, Ли Кашин / Li Ka-shing / 李嘉誠. Ищите на всех вариантах, включая оригинальное написание.
После первичного поиска (Слой 0, см. ниже) составьте список кандидатов: ФИО, год рождения (если есть), сфера, страна, работодатель.
| Ситуация | Что делать |
|---|---|
| Один кандидат | Собирать без уточнения |
| ≥ 2 кандидата, разные сферы | Задать вопрос с готовыми вариантами |
| ≥ 2 кандидата, одна сфера | Задать вопрос с признаком «работодатель / город / год» |
| Точного совпадения имени нет — только похожие | Задать вопрос: назвать ближайших, попросить признак |
| Один кандидат, но он широко известен | Собирать, но начать с оговорки о тёзке |
Один найденный кандидат — не доказательство, что он один. Порог считает тех, кого НАШЁЛ поиск, а не тех, кто существует. Непубличный человек следов не оставляет: у однофамильца-знаменитости статья в Википедии, а у директора по продажам из соседнего департамента — ничего. Поиск честно вернёт одного, и правило «один кандидат — собирать без уточнения» сработает на том, кого не спрашивали.
Признаки, что найденный — знаменитость, а не тот, кто нужен: статья в Википедии, государственная награда, федеральные СМИ, известность вне отрасли владельца. В этом случае досье собирается, но первой строкой идёт оговорка:
Нашёлся только широко известный <Имя> — <чем известен>. Если вы имели в виду однофамильца, назовите компанию, город или отрасль, и я соберу заново.
Вопрос здесь не блокирующий: чаще всего имелся в виду именно известный человек, и заставлять владельца отвечать на очевидное — потеря времени. Но одна строка сверху стоит дёшево, а встреча с чужой биографией в голове — дорого.
Реальный случай: на «кто такой <Имя Фамилия>» было выдано образцовое досье на известного однофамильца — основателя известного интернет-проекта, с источниками, ссылками и разделом «Не подтверждено». Спрашивали про другого человека — сотрудника крупной компании. Правило не нарушено: кандидат был один.
Прежде чем объявить двух кандидатов — проверьте, не один ли это человек в разные годы. Самая частая ложная развилка: у одного человека сменилась должность, поиск вернул две карточки, и они выглядят как двое.
Признаки, что это ОДИН человек:
Признаки, что это РАЗНЫЕ люди: разные работодатели в один и тот же период, разные отчества, разные годы рождения, несовместимые биографии.
Если сомневаетесь — спрашивайте не «кто из двух», а прямо:
Нашёл упоминания под двумя должностями в одной структуре; похоже, это один человек после повышения. Собираю как одного — поправьте, если это двое.
Реальный случай: на «<Имя Фамилия> из <компании>» было предложено два варианта с разными подразделениями одной компании. Это был один человек: в 2024 году он руководил одним направлением, а к 2025-му возглавил смежное. Тот же работодатель, непересекающиеся даты, смежные подразделения — все три признака слияния были на виду.
Только готовые варианты, не открытый вопрос. Слабая модель без вариантов получает расплывчатый ответ и продолжает угадывать.
Как задать вопрос. Коротко, с вариантами:
Есть как минимум две заметные тёзки. Про какую составить досье?
- <Имя> — <работодатель, роль>
- <Имя> — <работодатель, роль> Или уточните: работодатель / роль.
Чего делать нельзя:
Повторный запрос — не выбор человека. Если владелец снова пишет то же имя, он подтверждает интерес, а не назначает нового носителя. Переключаться на другого можно только по прямому указанию: имени, номера варианта, признака. История переписки таким указанием не является.
Реальный случай: на повторное «подготовь досье на <Имя Фамилия>» было выдано досье на другого человека с тем же именем, из другой страны, без единого вопроса. Руководитель получил чужую биографию.
Если сомневаетесь, о ком речь, — вопрос стоит одной строки, ошибка стоит встречи.
Норма — не меньше 40 поисковых запросов на досье. Замерено на живых прогонах: короткие сборы делали 5–10 запросов, и этого не хватало — биографические якоря оставались незакрытыми, а разделы наполнялись пересказом одного и того же источника. Сорок — это нижняя граница, а не цель: если после них якоря не закрыты, ищите дальше.
| Инструмент | Приоритет | Что даёт | Когда |
|---|---|---|---|
search.py этого навыка (Perplexity Sonar) | основной | связный ответ со ссылками — сам читает источники и замечает противоречия | все волны поиска |
browse_page | адресно | полный текст конкретной страницы | первоисточник, сниппета не хватает, надо проверить противоречие |
встроенный поиск агента (gigasearch, web_search) | запасной | зависит от установки, обычно не Sonar | только если search.py не работает (нет ключа, сбой) — и тогда это сказать в ответе |
Ищите через search.py, а не встроенным поиском агента. Встроенный поиск
в разных установках разный (внутренний поисковик, ddgs, OpenAI) и в живом
прогоне дал 4 запроса вместо 40. search.py ходит в Sonar по тому же ключу,
что и проверка фактов, принимает волну до 8 вопросов за вызов (идут
параллельно) и ведёт журнал запросов:
skill_exec(skill="dossier", script="search.py",
args=["Кто такой Иван Петров из компании «Пример»? Должность и с какого года",
"Ivan Petrov Primer company LinkedIn career",
"Иван Петров образование вуз год окончания"])
skill_exec(skill="dossier", script="search.py", args=["--log"]) # сколько уже сделано
Sonar понимает вопрос целиком — формулируйте вопросом, а не набором
ключевых слов: «Кто такой Иван Петров из компании «Пример», какую должность занимает и с какого года?»
Точечные операторы (site:, кавычки, OR) полезны для конкретных пробелов —
готовые формулировки в поисковом справочнике (см. ниже).
search.py исполняет запросы параллельно, до восьми за вызов. Отправляйте
волну одним вызовом, а не по одному запросу: один вызов — вся пачка текущего
слоя. Ритм: вызов поиска → адресные загрузки browse_page → снова поиск.
Волна 1 — установить личность (6–8 запросов). Полное имя, работодатель / организация, латиница, LinkedIn через выдачу, соцсети, однофамильцы.
Волна 2 — закрыть якоря (8–10 запросов). По каждому незакрытому якорю — свой запрос. Образование, годы, предыдущие работодатели, публикации, выступления, заявления.
После первичного сбора не переходите к анализу. Сначала выпишите подтверждённые опорные точки: последняя известная роль, работодатель, даты, прежние работодатели, образование, проекты, публикации и варианты написания имени.
Затем отдельной волной ищите информацию назад от каждой точки. Приоритет — восстановление карьерной хронологии: предыдущие роли, работодатели и промежутки между ними. Одновременно ищите другие публичные и релевантные факты из прошлого: проекты, сделки, выступления, публикации, профессиональные позиции и связи с организациями.
Каждый пробел в карьерном треке или значимом контексте — отдельный запрос, а не повод достраивать биографию по аналогии. Включайте найденное только при наличии источника и понятной связи с человеком.
Волна 3 — обход графа связей (6–10 запросов). Каждый новый именной объект из первых двух волн — работодатель, вуз, соавтор, конференция, сделка — порождает свой запрос. Без этого сбор останавливается на первом слое, и всё, что за ним, теряется.
Волна 4 — проверка спорного. Всё, что встретилось в одном источнике или разошлось между источниками, переспрашивается отдельно.
browse_page — не для всего подряд. Открывайте, когда: источник первичный
(сайт компании, раскрытие, реестр, интервью), или сниппета не хватает, или
надо проверить противоречие. Sonar уже прочитал многое сам — не дублируйте
его работу.
Норма — 20–30 открытых страниц. Ноль означает, что досье построено на одних сниппетах: для проверяемости этого мало.
Биография собирается обходом графа связей, а не одним запросом. Узлы графа: сам человек, работодатели, коллеги, соавторы, руководители, клиенты, конференции, издания. Рёбра: «работал в», «учился у», «выступал на», «писал вместе с».
1. ФИО полностью (с отчеством / middle name)
2. Год и место рождения
3. Гражданство / страна текущего проживания
4. Образование: вуз, факультет, годы, степень
5. Последнее известное место работы + должность + дата источника
6. Хронология работодателей (в обратном порядке)
7. Ключевые публикации / сделки / проекты / патенты
8. Публичные выступления от первого лица (интервью, подкасты, конференции)
9. Награды, звания, членство в советах
10. Публично заявленные позиции по отраслевым вопросам
Заполнено ≥ 7/10 → «данных достаточно». Меньше — «данных мало» (по индикаторам ниже).
Четыре слоя поиска, готовые формулировки запросов по типам пробелов,
доменные фильтры по регионам и отраслям, языковой протокол, приоритет
открытия результатов, стоп-условия и формат журнала якорей — всё это в
references/search-playbook.md.
Прочитайте его перед началом сбора — одним вызовом, без поиска пути:
skill_exec(skill="dossier", script="guide.py", args=["playbook"])
Там заготовки, которые экономят половину работы: без них запросы получаются общими, а поиск останавливается на первом слое.
Каждый факт несёт номер источника в квадратных скобках сразу после
утверждения: Возглавляет департамент с марта 2023 года [4]. Несколько
источников — подряд: [2][5].
Полные адреса — в разделе «Источники» в конце документа. Голых URL в теле быть не должно. Нумерация сквозная и не переиспользуется.
Место работы — «последнее известное», а не «работает сейчас».
Человек меняет работу непублично. Написать «сейчас работает в X» — утверждать то, чего источник не говорит: источник говорит, что на такую-то дату он там работал.
Возраст — с оговоркой, если выведен, а не прочитан.
Возраст в открытых источниках чаще не указан прямо: он выводится из года окончания вуза или первой должности. Такой вывод даёт диапазон.
Формула:
Возраст ≈ текущий_год − (год_поступления_в_вуз − 17)
≈ текущий_год − (год_первой_работы − 22)
Прямо названная в источнике цифра оговорки не требует: «48 лет [2]», — но учитывайте дату публикации: возраст на тот год, а не на сегодня.
Контрольные точки для сверки: год окончания вуза, год защиты диссертации, год первой руководящей должности, стаж в текущей роли. Расхождение между источниками — противоречие, а не повод выбрать цифру покрасивее.
Место жительства — только со связью с человеком.
Город из соцсети без подтверждающей связи — не источник вообще. По одному имени в соцсети находится десяток однофамильцев.
Город попадает в досье, только если подтверждён связью: адрес работодателя в том же городе, публичное выступление там, упоминание в деловой прессе с привязкой, его собственный пост о работе в компании из досье.
Нет связи → «место жительства не подтверждено», города в тексте нет. Неверный город на встрече — не мелочь: с него начинается small talk, ошибка вскрывается в первую минуту.
Ставится первой строкой досье в чате. Не в конце, не в примечании. В файл Word оценка не выводится (см. «Обязательные поля» ниже) — там её место занимает сама биография.
Индикаторы «мало данных» (выполнено ≥ 2 из 3):
Формулировка при «мало данных»:
Данных мало. Подтверждено: <перечислить>. Про манеру вести переговоры, приоритеты и стиль решений в открытых источниках сведений нет. Всё ниже опирается только на перечисленное; выводов о характере из этих фактов не делается.
Формулировка при «достаточно»:
Данных достаточно: /10 якорей закрыты, включая <сколько> из первых уст.
Раздел «Темы на обсуждение» при малых данных строится не от личности, а от роли: чем занимается его компания, что происходит в отрасли.
Досье к встрече не сдаётся сразу после написания. Отдельный проход проверки делают подагенты, а не тот же поток рассуждения. У подагента чистый контекст — он ищет подтверждение заново, а не защищает уже сделанные выводы.
Что проверяется — строго в этом порядке:
1) точная дата рождения / возраст
2) текущая должность и работодатель
3) ЛЮБОЕ число в тексте — деньги, проценты, количества людей,
клиентов, офисов, стран, лет стажа, мест в рейтингах
4) названные сделки, суммы, судебные споры
5) город проживания
Пункт 3 — именно ЛЮБОЕ число, а не только деньги и проценты. Выдуманное «аналитика для 1 млн+ частных инвесторов [1]» — счёт людей: при проверке «только денежных цифр» оно проскочило бы, а в источнике [1] его не было вовсе.
Как проверяется число — три шага, все обязательны:
Найти дословную формулировку. Откройте источник, на который ссылаетесь, и найдите число ГЛАЗАМИ в тексте. Не «источник про это», а «в источнике написано ровно так».
Подтвердить вторым независимым источником. Отдельным запросом к поиску — с самим утверждением, а не с именем человека:
skill_exec(skill="dossier", script="search.py",
args=["<название сервиса>: сколько частных инвесторов, 2026",
"«1 млн частных инвесторов» <название сервиса>"])
Sonar отвечает синтезом со ссылками — годится, если ссылки ведут на документ, где число стоит. Совпадение формулировки в двух перепечатках одного пресс-релиза за два источника не считается.
Записать доказательство в figures. Скрипт вёрстки требует на
каждое число либо дословную цитату источника, либо пометку, что оно
выведено. Процитировать то, чего в источнике нет, невозможно — на
этом проверка и держится.
Не нашли подтверждения — число из текста убирается, а утверждение остаётся без него: «аналитика для частных инвесторов [1]». Досье без числа полезно. Досье с выдуманным числом опасно: его понесут на встречу.
Всё остальное в кросс-проверку не идёт — оно уже подтверждено на Шаге 2.
Применение результата:
Если бюджет исчерпан — непроверенное переезжает в «Не подтверждено». Не «пропустили этот шаг».
<ОБЯЗАТЕЛЬНАЯ ПЕРВАЯ СТРОКА — оценка полноты данных (Шаг 4).>
# Досье: <Имя> (<оригинальное написание>)
Подготовлено: <дата> · Свежесть данных: <дата самого свежего источника>
## Одним абзацем
Кто это и почему важен для предстоящего разговора. 3–4 предложения.
## Кто он
Последнее известное место работы и должность — с датой источника.
Сколько лет в организации, чем занимался до. Возраст (по формуле, если
выведен) и образование. Каждый факт с номером источника.
## Чем известен
2–4 факта, по которым его знают в отрасли. Без оценок — оценки в блок
«[Анализ]».
## Культурный и национальный контекст
Заполняется, только если человек работает в другой деловой культуре
или разговор на стыке культур. Устойчивые деловые нормы страны,
а не стереотипы о людях. Для собеседника из той же среды, что и
владелец, — пропустить.
## Темы на обсуждение
Это единственный раздел про разговор: «о чём говорить» и «что обсуждать»
— один список, без деления надвое и повторов. Поле в JSON — `topics`.
Если пользователь не предоставил дополнительной информации в запросе, а просто
попросил подготовить досье на личность, то перечисляем 3–5 тем, каждая с
обоснованием и ссылкой на факт. Формулировать темой, а не вопросом. Готовый
вопрос звучит как анкета; тема даёт собеседникам самим найти формулировку.
Если пользователь дал в запросе контекст мероприятия или встречи (считаем
его по умолчанию существенным), нужен более развёрнутый список тем и
тезисов: каждая тема сводит повестку встречи с опытом человека, чтобы
разговор был максимально продуктивным. Раздел в таком случае имеет смысл расширить вплоть до 2800
знаков — это примерно страница документа Word, и весь документ тогда
занимает три страницы вместо двух.
## Чего не касаться
**Раздел не обязателен.** Заполнять, только если есть конкретика:
публичный конфликт, судебный спор, культурная специфика с закрытыми
темами, санкции. Если ничего — «специфических тем под запретом не
выявлено».
## Не подтверждено
Сведения без нужного числа источников и противоречия. Каждое — с
источником и указанием, чего не хватило. Противоречие — обеими версиями,
без выбора «более правдоподобной». Раздел обязателен: пусто — так и
пишите «нет».
## Анализ
Всё, что вывод, а не факт. Каждый блок помечен `**[Анализ]**` и опирается
на номера фактов. Раздел может быть пустым.
## Источники
Нумерованный список. Каждая строка: номер, название, дата, сила, ссылка.
1. [Годовой отчёт ПАО «X» за 2024 год](https://example.com/report-2024) —
15.03.2025 · сильный
2. [Интервью «Ведомостям»](https://example.com/interview) —
02.11.2024 · первое лицо
3. [Профиль в отраслевом справочнике](https://example.com/profile) —
дата не указана · слабый
Оформление не сочиняется каждый раз — его делает скрипт этого же навыка
render_dossier.py, а факты перед этим проверяет verify_facts.py. Модель
отвечает за содержание, скрипты — за проверку и вид. Вёрстка, которую
собирает сама модель, получается разной от прогона к прогону: то шрифт
применён к абзацам, но не к таблицам, то документ вырастает на пять страниц.
Свой скрипт вёрстки не пишите. Если вызов не прошёл — повторите.
Все пункты ниже реальные случаи из прогонов; каждый теперь — отказ сборки:
render_dossier.py сверяется с
тем, что подтвердил verify_facts.py (без --dry-run). Не подтверждено —
отказ. Флаг --unverified принимается только после настоящего сбоя:
verify_facts.py должен быть запущен (без --dry-run) и упасть из-за ключа,
отказа по ключу или сети — скрипт вёрстки это сверяет. «Решить, что ключа
нет», не запустив проверку, нельзя: в прогоне ключ был и Sonar работал.
После такого сбоя в документ первой строкой встаёт красная пометка
«триангуляция НЕ проводилась», в колонтитул — «БЕЗ ТРИАНГУЛЯЦИИ», а ответ в
чат обязан начинаться строкой «⚠️ Триангуляция НЕ отработала: <причина>».
Упомянуть это в конце ответа — нарушение.figures с дословной цитатой.search.py. Сборка сверяется с журналом search.py: если
за последние 12 часов нет ни одного успешного запроса Sonar с именем этого
человека — отказ. В прогоне агент прочитал инструкцию, сам написал «вижу шаг
search.py» и собрал всё встроенным поиском. Имя в запросе — кириллицей или
латиницей, одинаково. Исключение одно: Sonar недоступен (нет ключа, сеть), и
досье собирается с --unverified.Цитата в figures — на любом языке. Числа сравниваются как числа:
«$10 млрд» в досье и «$10 billion» в цитате — одно и то же, «79,1 млн» =
«79.1 million». Переводить цитату или подгонять запись не нужно. Совпадение
точное: «$3 трлн» не подтверждается «$3.1 trillion».
Текст для чата печатает скрипт. После сборки render_dossier.py выводит
блок «ТЕКСТ ДЛЯ ЧАТА» — из того же JSON, что и документ: первой строкой
полнота данных (или пометка о сбое триангуляции), последней — «Собрано: …».
Отправляйте его как есть, заменив только <МОДЕЛЬ>. Ничего не
добавляйте и не пересказывайте: в прогоне агент начал ответ с «Готово. Файл
отправлен.» и дописал в чат сведения, которые проверка из документа убрала.
Если и со второго раза нет, ручная сборка допустима, но о провале говорится ПЕРВОЙ строкой ответа, а не примечанием внизу:
⚠️ Триангуляция и штатная вёрстка НЕ отработали:
<текст ошибки>. Досье собрано вручную и через внешние источники НЕ проверено.
Та же пометка идёт и в итоговую строку «Собрано:». Причина жёсткости: в одном из прогонов оба скрипта были заблокированы, агент собрал документ руками и написал об этом абзацем в самом низу — владелец увидел обычное на вид досье и заметил подвох только в логах. Непроверенное досье внешне неотличимо от проверенного, поэтому отличать его должна первая строка.
Так уже было и хуже: однажды владелец получил вместо досье заглушку на четыре абзаца.
Шпаргалка по вызовам в одном месте:
skill_exec(skill="dossier", script="guide.py", args=["flow"]).
Где лежит рабочий файл. Сохраните dossier.json в рабочий каталог
текущей задачи и передавайте скриптам абсолютный путь. Если передано
только имя файла, скрипты сами ищут его в текущем каталоге, в каталоге
задачи (OUROBOROS_TASK_DRIVE) и в каталоге состояния навыка
(OUROBOROS_SKILL_STATE_DIR) и при неудаче печатают, где искали, — гадать
не нужно. На стандартной установке Ouroboros каталог задачи называется
task_drives, а не tasks:
/home/ouroboros/ouroboros-data/data/task_drives/<task_id>/dossier.json
Не помните task_id — возьмите его, не угадывая:
ls -dt /home/ouroboros/ouroboros-data/data/task_drives/*/ | head -1
Угадывание пути стоит дорого и повторяется из прогона в прогон: в одном из
прогонов агент четыре раза подряд получил отказ, читал исходники скриптов и
потратил на это около пятнадцати минут. Первая же попытка была
data/tasks/<id> — каталога с таким именем не существует.
1. Собрать содержание в JSON. Формат показывает сам скрипт — гадать не нужно. Вместе с полями он называет лимит каждого раздела и общий бюджет — пишите сразу под рамку, а не узнавайте её через отказ:
skill_exec(skill="dossier", script="render_dossier.py", args=["--schema"])
Поля совпадают с разделами досье один в один. Списочные разделы («Чем известен», «Темы на обсуждение», «Не подтверждено», «Анализ») — списками строк, остальные — строками.
Отдельно — поле figures. Туда идёт по записи на КАЖДОЕ число,
встречающееся в тексте досье:
"figures": [
{"value": "15", "source": 1,
"quote": "сегодня офисы компании работают в 15 странах"},
{"value": "около 47 лет", "source": 3,
"derived_from": "из года окончания вуза (2001) [3] — прямой даты рождения в источниках нет"}
]
quote — дословный кусок источника, в котором это число стоит, на
языке источника. Скрипт сверяет числа как числа («$10 млрд» = «$10 billion»):
если величины в цитате нет, документ не собирается.
derived_from — для выведенных чисел; тогда в тексте досье это число
обязано идти с «около» или «примерно», иначе скрипт тоже откажет.
Годы (1900–2099) и однозначные числа величинами не считаются.
Числа, для которых не нашлось ни цитаты, ни честного вывода, из текста убираются. Не «оцениваются», не округляются «примерно» — убираются.
2. Триангуляция — ДО чата и ДО документа:
skill_exec(skill="dossier", script="verify_facts.py",
args=["<абсолютный путь>/dossier.json"])
Это не формальность и не последний штрих. Порядок работы такой: волны поиска → кросс-проверка подагентами → этот скрипт → и только потом и текст в чат, и документ. Семь раз отмерь.
Почему до чата, а не перед вёрсткой: текст владелец читает из того же JSON, а не из файла. Проверка на выходе спасает документ и не спасает человека — он уже прочитал непроверенное.
Что делает скрипт: берёт КАЖДОЕ число и КАЖДУЮ фразу со ссылкой — предела нет, пропусков нет, — идёт с ними в Sonar в восемь потоков и считает домены, которые НА САМОМ ДЕЛЕ подтверждают (в сниппете есть само число или минимум два значимых слова утверждения); нужно не меньше двух РАЗНЫХ. Для чисел он вдобавок открывает саму цитируемую страницу и ищет число на ней: вопрос не «есть ли такое число где-нибудь», а «есть ли оно ТАМ, куда поставлена ссылка». Утверждения из уникальных первоисточников — LinkedIn, GitHub, arXiv, Google Scholar, ORCID — от кросс-проверки освобождены: требовать второй источник для того, что существует в одном месте, значит запретить верный факт.
Нужен ключ Perplexity: навык запрашивает PERPLEXITY_API_KEY из настроек,
владелец выдаёт доступ в карточке навыка. --dry-run показывает план
проверки без обращений к сети.
Если утверждений много и скрипт не уложился в отведённое время, он честно отвечает «НЕ ГОДИТСЯ — проверка не завершена» и запоминает уже подтверждённое: повторите тот же вызов, и он проверит только остаток.
Скрипт отказал — досье не отдаётся. Ни в чат, ни файлом. Убираете неподтверждённое число или переносите утверждение в «Не подтверждено» и прогоняете снова. Проверка стоит минуты; досье с выдумкой уносят на встречу.
3. Проверить объём и числа до сборки:
skill_exec(skill="dossier", script="render_dossier.py",
args=["--check", "<абсолютный путь>/dossier.json"])
Скрипт покажет знаки по каждому разделу и его лимит. Превышение — отказ, а не предупреждение: документ на три страницы никто не читает перед встречей. Отказывает и лимит отдельного раздела, а не только общий объём.
3а. Если превышен объём — дайте срезать скрипту:
skill_exec(skill="dossier", script="render_dossier.py",
args=["--fit", "<абсолютный путь>/dossier.json"])
Скрипт сам убирает необязательное по правилу — «Анализ» → «Культурный контекст» → примеры в «Чем известен» — пока и общий бюджет, и лимиты этих разделов не сойдутся. Что убрано, он перечисляет вслух и дописывает пометку в «Не подтверждено»: документ не должен выглядеть полным, если из него вынули часть. Результат пишется в тот же файл, если он лежит в рабочем каталоге навыка или задачи, иначе — рядом, в рабочий каталог, и скрипт печатает путь.
Прозу обязательных разделов — «Кто он/она», «Одним абзацем» — скрипт не режет:
обрывать биографию на полуслове хуже, чем отказать. Их сокращаете вы, и
--check называет конкретную цель: не «сократите», а «сократите до 540
знаков». Цель ниже лимита намеренно: разделы считаются вместе, и, срезав
ровно превышение, вы промахнётесь снова.
4. Собрать файл:
skill_exec(skill="dossier", script="render_dossier.py",
args=["<абсолютный путь>/dossier.json", "Досье — <Фамилия Имя> — <ГГГГ-ММ-ДД>.docx"])
Имя файла — без путей, только <имя>.docx: скрипт пишет строго внутрь
своего рабочего каталога и печатает полный путь готового файла. Этот путь
и передавайте в send_file.
5. Ответ в чат — готовый блок из вывода скрипта. Скрипт печатает
«ТЕКСТ ДЛЯ ЧАТА»; отправьте его целиком, заменив только <МОДЕЛЬ>. Его
последняя строка — чем собрано, в таком формате:
Собрано: dossier v<версия> · проверка verify_facts · вёрстка render_dossier · модель <какая отвечала>
Модель берите ту, что реально отвечала, а не ту, что задана основной: при отказе основной работу подхватывает запасная, и владельцу важно знать, кто именно собирал. Хорошее качество давали Sonnet 4.6 и GLM-5.2 — по этой строке видно, чему верить.
Если триангуляция или вёрстка не отработали, это пишется в той же строке, а не в примечании внизу:
Собрано: dossier v<версия> · БЕЗ ТРИАНГУЛЯЦИИ · вёрстка render_dossier · модель <какая отвечала>
6. Отдать файл владельцу через send_file, и тем же ходом — блок
«ТЕКСТ ДЛЯ ЧАТА» из шага 5.
gender — "m" или "f". От него зависят заголовки: «Кто он» / «Кто она»,
«Чем известен» / «Чем известна». Досье о женщине с заголовком «Кто он»
выглядит собранным без внимания, и это замечают в первую секунду.
Определяйте по источникам, а не по имени: имя не всегда однозначно.
meeting_context — заполняется, если владелец дал контекст встречи:
повод, формат, площадка, чего он хочет добиться. Считайте такой контекст
существенным по умолчанию. При заполненном поле скрипт сам расширяет
«Темы на обсуждение» до 2800 знаков, а документ — до трёх страниц.
completeness — оценка полноты. Считается всегда, но в документ не
выводится: якоря и счёт источников нужны вам, чтобы решить, хватает ли
материала. Руководитель открывает досье, чтобы узнать человека, а не
оценивать работу над ним. В чате оценка остаётся.
Досье целиком по-русски. Единственное исключение — оригинальные названия
организаций и аббревиатуры: Associação Comercial de São Paulo (ACSP),
BNP Paribas, En+. Всё остальное переводится, включая месяцы в датах:
«по состоянию на agosto 2026» — недоделка, даже когда факт верен.
Цитаты из англоязычных источников в тексте разделов тоже переводятся:
«Narendra Modi has served as Prime Minister since 2014» в «Кто он» —
брак, даже если факт верен. Дословный оригинал нужен только в figures.quote.
Скрипт подстраховывает и сам переводит месяцы в дате шапки, но полагаться на это нельзя: он не трогает текст разделов.
w:eastAsia, иначе Word подставит свой шрифт.figures.Сокращать строго в этом порядке: «Анализ» → «Культурный контекст» → примеры внутри «Чем известен». Никогда не сокращать полноту данных, «Не подтверждено» и «Источники» — без них документ теряет то, ради чего он честен.
Чат и документ содержат одно и то же. Не краткий пересказ и не выжимка: тот же текст, те же разделы, тот же порядок, те же 5400 знаков (или 8100, если задан контекст встречи).
Если в чат идёт выжимка на 300–600 слов, а в файл — две страницы, получается два разных досье: одно читают сразу, второе открывают позже и находят там другое. Расхождение между тем, что человек прочёл, и тем, что он переслал помощнику, — источник недоразумений на встрече.
Отличается только оформление:
| В чате | В документе | |
|---|---|---|
| Заголовки | ## | стили Word |
| Ссылки | [1] инлайн | [1] + таблица с гиперссылками |
| Полнота данных | есть, первой строкой | не выводится |
| Заголовки по роду | «Кто она» | «Кто она» |
Полнота данных — единственное, что есть в чате и нет в документе: вам она нужна, чтобы понять, насколько досье надёжно, а в файле, который уйдёт дальше, служебная арифметика лишняя.
Проверяется по порядку. Любой невыполненный пункт — досье не сдаётся.
search.py (журнал: search.py --log); запросов
не меньше 40, открытых страниц 20–30figures
с цитатой; порядок величины ниоткуда не дописанmeeting_context заполнен, а
«Темы на обсуждение» развёрнуты (до 2800 знаков) и сводят повестку
встречи с опытом человекаverify_facts.py прошёл начисто — до текста в чат и до документа;
неподтверждённые утверждения убраны или перенесены в «Не подтверждено»render_dossier.py --check прошёл: бюджет и лимиты разделов не превышеныfigures--unverified; если с ним — первая строка ответа
«⚠️ Триангуляция НЕ отработала: <причина>»send_filegender заполнено — заголовки «Кто она» / «Чем известна» верны