Skip to main content
Glama

OfferUpBot

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

Руководство для агентов

Агенты, работающие без истории переписки, начинают с AGENTS.md. Для прямого исполнения OfferUp используется skills/operating-offerupbot/SKILL.md; для полного цикла владения физическим товаром — skills/operating-seller-operator/SKILL.md; для существенной аналитики изображений — skills/inspecting-visual-evidence/SKILL.md. Каждый навык подгружает более глубокие материалы только тогда, когда это требуется задачей.

Режим исполнения

Интерфейс по умолчанию — MCP stdio по требованию:

agent launches OfferUpBot
        ↓
MCP tools execute against shared SQLite state and browser profile
        ↓
agent disconnects
        ↓
OfferUpBot exits

Состояние сохраняется между вызовами в SQLite и выделенном профиле браузера OfferUp. Процесс по умолчанию не запускает планировщик, HTTP-слушатель или фоновый монитор.

Непрерывный режим monitor необязателен и по умолчанию отключён. Команда run:due выполняет один явный навёрстывающий проход и завершается.

Требования

  • macOS с установленным Google Chrome для авторизованных операций

  • Node.js 22 или новее

  • pnpm

Не требуется Docker, внешняя база данных, Redis или отдельно управляемый сервис времени выполнения.

Установка и сборка

git clone https://github.com/yinkev/OfferUpBot.git
cd OfferUpBot
pnpm install
pnpm build

Запустите сборочную точку входа разработки MCP:

pnpm mcp

Запустите собранную точку входа:

pnpm start

Каталог данных по умолчанию:

~/.offerupbot/
├── state.sqlite
├── browser-profile/
└── agents.json          # only after restricted agents are created

Переопределите его с помощью OFFERUPBOT_DATA_DIR, когда требуется изоляция.

Вход в OfferUp

pnpm auth:login

Откроется отдельное окно Chrome. Введите учётные данные непосредственно на OfferUp. Вход принимается только когда авторизованный запрос учётной записи OfferUp возвращает реальный ID аккаунта. Учётные данные не запрашиваются через чат и не сохраняются в SQLite.

Настройка MCP

После pnpm build укажите в х её агента на собранную точку входа stdio:

{
  "mcpServers": {
    "offerupbot": {
      "command": "node",
      "args": [
        "/absolute/path/to/OfferUpBot/dist/src/index.js"
      ],
      "env": {
        "OFFERUPBOT_DATA_DIR": "/absolute/path/to/.offerupbot"
      }
    }
  }
}

Без токена агента локальный процесс stdio работает как доверенный полный оператор.

Создайте ограниченную сущность, когда агенту нужны более узкие полномочия:

pnpm agent:create -- \
  --id research-agent \
  --name "Research Agent" \
  --permissions market.read,events.read,watch.manage

Сохраните возвращённый токен в MCP-окружении этого агента как OFFERUPBOT_AGENT_TOKEN. OfferUpBot хранит только его SHA-256-хэш.

Инструменты агента

Tool

Purpose

Permission

offerup.health

Состояние локального рантайма и кэшированных сессий

нет

offerup.auth_status

Проверка текущей учётной записи и возможностей OfferUp

account.read

offerup.research_market

Поиск с проверенными фильтрами OfferUp

market.read

offerup.inspect_listing

Полный набор доказательств по объявлению; при download_photos — кэширование упорядоченных фото как локальных файлов

market.read

offerup.watch_market

Дать способность создавать, просматривать, приостанавливать, возобновлять, удалять или запускать наблюдение

watch.manage

offerup.run_due

Выполнить каждое просроченное наблюдение один раз

watch.manage

offerup.next_events

Читать и подтверждать долговечные события

events.read

offerup.sync_listings

Синхронизировать активное, архивное и охранённое состояние аккаунта

account.read

offerup.sync_inbox

Синхронизировать потоки входящих и изменения в сообщениях покупателя

account.read

offerup.get_thread

Получить один полный диалог и контекст объявления

account.read

offerup.send_message

Отправить одно идемпотентное, внешне проверенное сообщение

message.send

offerup.validate_listing

Проверить текущий контракт объявления для покупателя

нет

offerup.publish_listing

Опубликовать и проверить объявление

listing.publish

offerup.update_listing

Отредактировать и проверить поддерживаемые поля

listing.update

offerup.close_listing

Пометить как проданное или архивировать, затем проверить состояние аккаунта

listing.close

Начните с skills/operating-offerupbot/SKILL.md; в соседних REFERENCE.md и WORKFLOWS.md содержатся подробные контакты и процедуры.

Инструменты продавца-оператора

Над инструментами исполнения находится второй слой интерфейса MCP для агентов, которые владеют физическими товарами и администрируют их на всём пути: 30 инструментов seller.*, покрывающих приём заявок и предметов, фотографий и доказательств с отслеживаемым происхождением, OCR/детерминированное распознавание и выбор идентичности, уточнение достаточности доказательств, исследование рыночных аналогов, решения о цене и о судьбе предмета, обоснованные черновики объявлений с проверенной публикацией и закрытием, классификацию покупалиц, предложения, эксклюзивные бронирования, встречи (с проверкой конфликтующих событий и идемпотентными напоминаниями), вероятностный цикл оператора по отложенным задачам, запись результатов передачи и аналитику жизненного цикла.

Права: seller.read (чтение, просмотр), seller.write (доменные записи; публикация и закрытие также требуют listing.publish и listing.close), seller.communicate (действия с покупателями). Сообщения по-прежнему проходят через проверяемый offerup.send_message. Начните с skills/operating-seller-operator/SKILL.md; в соседних REFERENCE.md и WORKFLOWS.md содержится руководство по доказательствам, рынку, покупателям и жизненному циклу.

Идентификаторы и записи

OfferUp использует два разных идентификатора объявлений:

  • listing_id: UUID, используемый для публичных данных, диалогов, проверки и передачи в мутации редактирования.

  • item_id: числовой идентификатор в инвентаре продавца, используемый в /selling, при отметке как проданное и при архивации.

Каждый значимый инструмент требует устойчивый идемпотентный ключ. Используйте тот же ключ повторно после таймаута или сбоя. При смене ключа попытка восстановления может превратиться в дублирующее внешнее действие.

Явные режимы планирования

Выполните все просроченные наблюдения один раз и завершитесь:

pnpm run:due

Удерживаете работу планировщика наблюдений на переднем плане только тогда, когда намеренно нужно непрерывное опрашивание:

pnpm monitor

Режим monitor никогда не запускается командами pnpm mcp, pnpm start, при установке или входе. Его закрытие останавливает непрерывный опрос. Последующий вызов run:due или MCP-команды offerup.run_due догоняет состояние из сохранённых наблюдений.

Поверхность передачи (по желанию)

Команда pnpm handoff запускает маленькую HTTP-поверхность на переднем плане для единственной человеческой точки: личная передача. Она показывает карточки передачи, ожидающие выполнения (покупатель, согласованная цена, назначенная встреча, аксессуары, дефекты, политика оплаты, резервные покупалители) на GET /, предоставляет GET /api/handoffs и записывает результат по через POST /api/handoffs/:itemId/result в то же SQLite-состояние.

Она привязана к 127.0.0.1 (переопределяется переменными OFFERUPBOT_HANDOFF_HOST/OFFERUPBOT_HANDOFF_PORT) и требует bearer-токен из OFFERUPBOT_HANDOFF_TOKEN; если токен не установлен, он генерируется и печатается один раз при запуске. Как и monitor, она никогда не запускается чем-либо ещё: исполнение по умолчанию остаётся MCP stdio по требованию без слушателя.

Семантика сбоев

Запись считается завершённой только когда её ответ содержит verified: true.

Важные коды:

  • OFFERUP_SESSION_EXPIRED / AUTH_REQUIRED: выполните полный вход в OfferUp перед авторизованной работой.

  • RESOURCE_BUSY: другой процесс держит учётную запись или аренду браузера; повторите позже с тем же идемпотентным ключом.

  • RESOURCE_LOCK_LOST: не считайте, что запись завершена; вызовите релевантный инструмент чтения или синхронизации и только потом повторяйте.

  • IDEMPOTENCY_CONFLICT: то же самый ключ представлен с другим намерением; согласуйте состояние вызывающего агента.

  • OFFERUP_FILTER_MISMATCH: OfferUp молча проигнорировал ограничение поиска; не используйте результат как валидные рыночные аналоги.

  • AUTO_CATEGORY_MISMATCH: OfferUp применил категорию, отличную от поданного черновика.

  • CATEGORY_PATH_NOT_TERMINAL: путь остановился на родительской категории, а не на финальной выбираемой категории.

Проверка

Проверка в обычном режиме:

pnpm test
pnpm typecheck
pnpm build

Живая проверка «только для чтения» против настроенного профиля OfferUp и публичной страницы:

OFFERUPBOT_LIVE_TESTS=1 pnpm exec tsx --test \
  tests/account/live.test.ts \
  tests/auth/live.test.ts \
  tests/offerup/public/live.test.ts

Безопасная перехваченная приёмка контрактов на запись:

OFFERUPBOT_LIVE=1 pnpm exec tsx --test --test-concurrency=1 \
  tests/messages/live-direct.test.ts \
  tests/listings/live-browser.test.ts \
  tests/listings/live-close.test.ts

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

Текущая границ обжатия

Код, публичные обращения, авторизованные чтения, текущие веб-мутации сообщений, контракт публикации/редактирования для покупательских объявлений и мутации закрытия реализованы и протестированы. Контролируемый агент-тест в памяти покрывает исследования, публикацию, входящие, сообщение, обновление и закрытие.

Целевой реальный цикл объявления был выполнен 24 июля 2026 года на вой настроенном приёмочном аккаунте: Philips Norelco BG7030/49 был опубликован с шестью файлами, подтверждён внешней проверкой, обновлён с $60 до $55 и проверен повторно без потери состояния New, затем архивирован и проверен в авторизованном инвентаре как UNLISTED. Прогон показал и закрыл два живых дефекта: выборвыбор информации о категории при внешне видимом диалоге публикации, и потерю состояния при правке только цены.

Оставшийся реальный транспортный шар был закрытия в тот же день: offerup.send_message отправил одно предложение $50 наличными через прямой адаптер, возвращённый ID сообщения был перечитан в этом же диалоге и авторизованная синхронизация входящих подтвердила переписку. Продавец позже ответил: «Это покемонический центр по ошибке,» — при выяснении неверной логики. Первое фото объявления явно идентифицировало эксклюзивного варианта Pokémon Center, но агент оценивал стандартный ETB. Точный продукт в TCGplayer 692949 был около $120, поэтому предложение $50 составляло около 42% от точной рыночной цены — не 78%. Проверка «ровно один раз» прошла, провалилисьей идентификация варианта, оценка и выбор цели. Полный анализ в docs/acceptance/2026-08-24-real-message-send.md.

Оба назначенных транспортных приёма значущих записей завершены. Будущие реальные записи по-прежнему требуют явно выделенного объявления или диалога; повторяемые регрессы остаются перехваченными и не должны изменять произвольные объекты аккаунта.

Слой продавца-оператора (добавлен в 2026-08)

Поверх исполнительного слоя находится система продавца-оператора: канонические физические позиции с отслеживаемым происхождением доказательств, разрешение сущностных личностей, исследование рынка и цен с разделением реализованных и активных аналогов, управляемая публикационная оркестрация, состояние покупателя/предложения/брони/встречи, запись результатов передачи и восстанов парируемый контекст дела. Она полностью включена в промышленный рантайм (вse schemas at startup; runtime.runDue() выполняет catch-up проход по наблюдениям и задачами продавца; синхронизация листингов добавляет ряды views/discussions/prices) и доступна через инструменты seller.* выше.

Дополнительные интеграции — все по умолчанию выключены:

  • OFFERUPBOT_READ_ONLY=1 — блокирует любые значимые записи OfferUp (опубликовать, обновить, закрыть, отправить — либо через организацию).

  • OFFERUPBOT_EBAY_CLIENT_ID / OFFERUPBOT_EBAY_CLIENT_SECRET — включает источниканный eBay-аналоги (активные цены и проданные, официальые API). При отсутствии эти источники сообщают о недоступности, поиск остаётся пустым; ничего не скрапится.

  • OCR выполняется через macOS Vision, когда она есть (darwin + osascript), и в остальных случаях программно падает на детерминированное извлечение.

Аналитика исходов (src/analytics) вычисляет полный набор метрик как для проданных, так и для непроданных товаров, а категориальные априорные распределения (ограниченные, скорректированные по размеру выборки и фиксируемые в обосновании решения), полученные из завершённых исходов, используются в ценообразовании и распоряжении товарами. См. docs/seller-operator-architecture.md для карты слоёв и инвариантов, docs/seller-operator-tracker.md для статуса сборки и tests/e2e/seller-operator.test.ts для контролируемого приёмочного теста полного жизненного цикла (мокированные внешние записи — без реальных мутаций маркетплейса).

Maintenance

ActivityMaintained
ResponsivenessSyncing

Related MCP Connectors