# Mantia

Антидетект-браузер со встроенным ИИ-агентом. Вы ставите задачу словами —
агент открывает профиль и делает её сам, живым вводом, в реальном Chrome.

Управление браузером — сырой CDP, без Playwright и Selenium: оба палятся на
ровном месте (Playwright инжектит служебный isolated world, chromedriver
добавляет `cdc_*` в документ).

---

## Установка (закрытая альфа)

Работает на **Windows 10/11** и на **macOS**. Нужен Python 3.11+.

Архив берётся по ссылке, которую вам дали вместе с доступом. Ссылка непубличная
и нигде на сайте не значится — она и есть пропуск в закрытую альфу.

**Windows.** Распакуйте архив, откройте папку и запустите:

```bash
powershell -ExecutionPolicy Bypass -File install.ps1
```

**macOS.** В папке проекта:

```bash
uv venv && uv pip install -e .
.venv/bin/mantia install-app
```

Вторая команда кладёт `Mantia.app` в Launchpad — дальше программа
запускается щелчком, а не из терминала. Она запоминает путь к тому
интерпретатору, которым вы её поставили, поэтому после переезда venv команду
надо повторить.

Дальше на обеих системах одно и то же:

```bash
mantia fetch-chromium   # браузер для профилей, ~150 МБ
mantia capture-ua       # снять эталон с вашего обычного Chrome
mantia check            # что готово, чего не хватает
```

### Обновления

Впишите в `.env` рядом с данными строку, которую вам дали вместе со ссылкой:

```
MANTIA_UPDATE_URL=https://…/latest.json
```

После этого:

```bash
mantia version   # своя версия и вышла ли новее
mantia update    # скачать, сверить контрольную сумму и распаковать рядом
```

`update` **не подменяет** работающую программу: новая версия ложится в
отдельную папку внутри ваших данных, а перейти на неё вы решаете сами — закрыть
окно и поставить оттуда. Причина не в осторожности ради осторожности: на
Windows работающая программа держит свои файлы открытыми, а подмена кода при
открытом профиле обрывает сессию живого аккаунта.

Профили, база и `.env` при обновлении не трогаются вовсе — они лежат отдельно
от программы. Контрольная сумма архива сверяется ДО распаковки: архив едет по
чужой сети, и распаковать непроверенный — значит выполнить чужой код на машине,
где лежат ваши аккаунты.

Если строка не вписана, продукт про обновления молчит и никуда ничего не
спрашивает.

`mantia check` отвечает по-человечески: что не готово и что с этим делать.
Начинайте с него — он же скажет, готов ли второй уровень (о нём ниже) и есть
ли доступ к модели.

### Доступ к модели

Агенту нужна модель. Ключ покупать НЕ обязательно: по умолчанию продукт
ходит через установленную у вас программу `claude` по вашей подписке.

```
MANTIA_LLM_PROVIDER=claude-cli     # подписка, ключ не нужен
```

Если хотите по ключу — тот же файл `.env` рядом с данными:

```
MANTIA_LLM_PROVIDER=groq           # или anthropic, или openai
MANTIA_LLM_API_KEY=<ваш ключ>
```

Без доступа к модели профили открываются и работают руками — недоступны
только задачи агенту.

Данные (профили, база, логи, `.env`) лежат вне папки программы: на Windows в
`C:\mantia`, на macOS в `~/.mantia`. Путь короткий намеренно: каталоги
профилей Chromium упираются в лимит 260 символов.

---

## Два уровня, и чем они отличаются

Выбор делается при создании профиля, и продукт честно называет цену каждого.

**«Свой отпечаток» — максимум доверия.** Профиль работает на НАСТОЯЩЕМ
отпечатке вашей машины. Подделывать нечего, значит и поймать не на чем.
Цена: разных отпечатков на одной машине мало — ровно столько, сколько у неё
способов рисовать. На машине с двумя видеокартами это четыре; профили сверх
этого числа площадка увидит как одно устройство. `mantia doctor` показывает
ваше число.

**«Масштабирование» — много профилей на одну площадку.** Отпечаток
подменяется в самом браузере, а не скриптом на странице: у каждого профиля
свои экран, ядра, видеокарта, шрифты, голоса и звук, и они не меняются между
запусками. Цена: это **Firefox, а не Chrome**, и памяти нужно 1,10 ГиБ на
профиль против 0,45.

Ещё одна цена, о которой лучше знать заранее: **система профиля равна системе
вашей машины**. Выдать Windows-профиль с макбука нельзя — шрифты чужой
системы физически не подключаются, и профиль остаётся вообще без шрифтов.
Windows-профили выдаёт машина на Windows или на Linux.

---

## Как пользоваться

**1. Создайте профиль.** Кнопка «Создать профиль»: имя, площадка, страна,
прокси. Прокси принимается во всех трёх привычных форматах —
`host:port:логин:пароль`, `логин:пароль@host:port` и
`socks5://логин:пароль@host:port`. Кнопка
«Проверить» бьёт через прокси наружу и показывает реальный внешний IP и
задержку: если прокси мёртв, вы узнаете это до запуска, а не в середине
задачи.

**1а. Своя площадка.** Встроенных пресетов два — Grailed и Etsy, — но список
ими не заканчивается. Настройки → раздел «Площадки» → кнопка «Добавить свою»:
домен, название и стартовый адрес. Дальше своя площадка выбирается при
создании профиля наравне со встроенными.

Стартовый адрес обязан быть на её же домене или поддомене. Пресет с одним
доменом и адресом на другом увёл бы агента на чужой сайт В ЭТОМ ЖЕ профиле, а
профиль хранит куки и вход именно этой площадки.

У своей площадки нет адаптера, и в списке она помечена «без адаптера». Разница
такая: агент на ней работает — он видит страницу деревом доступности и ищет по
смыслу, а не по вёрстке. А вот **сценарии не компилируются**. Сценарий — это
записанный путь удачного прогона: на знакомой площадке следующая такая же
задача идёт по нему, без модели и без её цены. На своей площадке каждый прогон
идёт через модель заново.

**2. Запустите профиль.** Кнопка ▶ открывает окно Chrome с этой личностью:
свой отпечаток, свой прокси, своя таймзона. Войдите руками в нужный аккаунт
— пароль набирается вами и **в модель не попадает никогда** (§3 п.9: секреты
идут в браузер мимо контекста агента и не могут быть возвращены как
значение).

**3. Дайте задачу.** Панель агента справа. Пишите словами: «найди на Grailed
кроссовки Nike до 200 долларов и собери ссылки». Агент видит страницу как
дерево доступности, двигает мышь по кривым Безье с тремором и печатает с
задержками живого человека.

Если агент упирается в проверку (капча, подтверждение) — он **останавливается
и зовёт вас**, а не пытается её обойти. Это осознанная граница, см. ниже.

**4. Много профилей — одна задача (флот).** Кнопка «Пачкой» заводит сразу
десяток профилей, а задача ставится им всем разом. Старты разносятся по
времени случайно: сотня аккаунтов, стартующих в одну секунду, связывается по
времени безо всякого отпечатка. Продукт сам считает, сколько браузеров
потянет машина, и предупреждает, если в пачке смешаны уровни — у них разное
доверие площадки.

**5. Перенос на другую машину.** Настройки → «Аккаунт и машины». Задайте
парольную фразу и нажмите «Выгрузить флот в файл» — программа назовёт точный
путь. На второй машине «Загрузить файл с другой машины» и та же фраза.

Переезжают метаданные и пароли прокси. **Каталоги профилей — нет**, и это не
недоделка: куки, приехавшие на другое железо, для площадки выглядят как вход в
старую сессию с нового устройства. Профили той машины видны в списке с пометкой
«на другой машине» и кнопкой «забрать сюда», которая сначала объясняет цену.

---

## Чего продукт не умеет — честно

Этот список нужен раньше, чем список возможностей: обещание, которое не
сбудется, стоит доверия один раз и навсегда.

* **Профилей с разным отпечатком на одной машине ограниченное число** — на
  первом уровне столько, сколько у машины способов рисовать. Для десятков
  профилей берите второй уровень.
* **Второй уровень — Firefox.** Где площадка ждёт именно Chrome, он не
  подойдёт.
* **Холст на втором уровне общий для всех профилей одной машины.** Замерено:
  профили с разными наборами шрифтов рисуют побайтово одно и то же там, где
  букв нет. Площадка, снимающая холст, связывает такие профили одним запросом.
  Правка для этого написана и проверена на своей сборке, но в поставку пока не
  входит (`build/camoufox/`). Пока не входит — карта покрытия показывает холст
  как проблемное место, а не как защищённое.
* **Систему профиля нельзя выбрать произвольно** — она равна системе машины
  (кроме Linux, который умеет выдавать Windows).
* **Сеть выдаёт прокси, а не профиль.** Отпечаток сетевого стека принадлежит
  выходному узлу: браузер говорит «Windows», а пакеты приходят со стека
  Linux-сервера, если прокси дата-центровый. Из браузера это не чинится
  ничем. Резидентные и мобильные прокси проходят такие проверки, но они в
  несколько раз медленнее — замерено: 0,4 секунды против 2,0 на один запрос.
* **Капчу и проверки личности продукт не обходит.** Агент, упёршийся в них,
  останавливается и зовёт человека. Это не недоделка, а граница.
* **Пароли агент не набирает** и в контекст модели они не попадают никогда.

## Что внутри, кратко

| Что | Как сделано и почему |
|---|---|
| Отпечаток | Пул сборок Chrome for Testing + UA-CH из эталона настоящего Chrome. Одна версия на всех — когортный признак, поэтому пул. |
| Ввод | `Input.dispatch*` пачками по кадру с нарастающим `timestamp`. Даёт `isTrusted: true` и правильное склеивание событий. |
| Восприятие | AX-дерево + точная геометрия и hit-тест. CSS-модули дают нестабильные хэши классов — по ним целиться нельзя. |
| Прокси | Локальный SOCKS5-форвардер на профиль, fail-closed: смерть форвардера даёт ошибку, а не прямое соединение с вашего IP. |
| Надёжность | Журнал шагов, чекпойнты, аренда с fencing-токеном, транзакционный outbox. Прогон переживает перезапуск. |
| Ночной прогон | Планировщик по часам персоны, размыкатель на живых сигналах, утренний дайджест «7 падений = 2 причины». |

Данные — вне репозитория, в `MANTIA_HOME` (по умолчанию `C:\mantia`):
профили, прогоны, сборки Chromium, база, секреты. Причина не только гигиена:
`user-data-dir` профиля это состояние личности, и случайный `git clean -xfd`
не должен его уничтожать.

---

## Что уже нельзя нарушить

Эти инварианты держатся тестами, а не соглашениями:

- `Runtime.enable` не отправляется никогда; JS исполняется только в
  изолированном мире, и происхождение `contextId` проверяется по реестру;
- `navigator.webdriver === false` — hard fail при ином;
- ввод только через `Input.dispatch*`, событиями с нарастающим `timestamp`
  пачками по кадру;
- прокси fail-closed;
- один аккаунт ↔ один профиль ↔ один прокси — констрейнтами в БД;
- пароль невозможно получить как возвращаемое значение.

## Границы

Строится универсальный инструмент автоматизации браузера и управления
профилями. **Не строится:** обход CAPTCHA, обход liveness/KYC-проверок,
подмена видеопотока для верификации личности, автоматическая массовая
регистрация аккаунтов.

---

## Разработка

Начинать с [docs/handover.md](docs/handover.md): там причины принятых решений,
уже совершённые ошибки и порядок дальнейших работ. Код отвечает на «что», этот
документ — на «почему».

Нормативное техзадание — [docs/PLAN-antidetect-browser.md](docs/PLAN-antidetect-browser.md).
При расхождении прав оно, а не код.

```bash
uv venv && uv pip install -e .          # на Windows: -e ".[windows]"
uv pip install pytest pytest-asyncio ruff mypy

pytest tests/unit -q              # быстрые, без браузера
pytest tests/live -m live -q      # приёмка этапов, нужен Chrome и прокси
ruff check src tests
```

Раскладка:

```
src/mantia/
├── core/        типы, ошибки, ULID, дедлайн, контекст прогона, профиль хоста
├── cdp/         FlagBuilder, ChromeProcess, Connection, DomainActivator, Readiness, Policy
├── observe/     AX-дерево, геометрия, снимок страницы, PageObserver
├── input/       моторный профиль, траектории, HumanInput
├── identity/    профили, SOCKS5-форвардер, SecretStore, UA-эталоны, выдача профилей
├── durable/     журнал, чекпойнты, аренда, outbox
├── runner/      сессия, планировщик, размыкатель, дайджест
├── agent/       LLMGate, промпты, цикл агента
├── api/         локальный сервер и интерфейс
└── …            sites, scenario, storage, policy, intervention, sinks, cli
tests/unit       без браузера
tests/live       приёмка этапов, нужен браузер
spikes/          измерения этапа 0 + probes/
docs/            progress.md — что измерено и что из-за этого изменилось
```

Полное техзадание — `PLAN-antidetect-browser.md`.
Результаты замеров и изменения плана — [docs/progress.md](docs/progress.md).
