Plank help · updated 2026-09-17

Скрипты рабочего пространства и боковая панель

Как короткий заголовок @plank-integration в скрипте рабочего пространства добавляет его в раздел «Интеграции» на боковой панели, сгруппировав по провайдеру.

Agents: fetch the raw markdown of this page at /ru/help/workspace-scripts.md

Скрипты рабочего пространства и боковая панель

В вашем рабочем пространстве на боковой панели есть раздел Интеграции. Это единственное место, где собрано всё, что агент может запустить во внешнем сервисе — ваши скрипты автоматизации, а также учётные данные и подключения за ними — сгруппированное по тому, с каким провайдером они работают (Google, Stripe, Slack, OpenAI и так далее).

Скрипт появляется там после того, как вы добавите в его начало короткий заголовок @plank-integration. Этот заголовок — ваше согласие: он сообщает Plank «это файл-интеграция, и вот провайдер, к которому он относится».

Что появляется на боковой панели

Раздел «Интеграции» организован по провайдерам. Под каждым провайдером вы увидите скрипты (инструменты), которые с ним работают, сгруппированные по сервису, вместе со всеми сохранёнными учётными данными и подключениями для этого провайдера. Строка провайдера появляется, только если к нему привязано хотя бы что-то одно — пустых строк не бывает.

Если ещё ничего не настроено, в разделе показывается короткое сообщение «нет интеграций» со ссылкой Обзор. Кнопка + рядом с заголовком раздела (и эта ссылка) открывает новый чат с заготовленным запросом на настройку, чтобы агент мог провести вас через подключение сервиса и написать скрипт за вас.

Заголовок @plank-integration

Чтобы добавить скрипт на боковую панель, поместите в его начало блок комментариев. Используйте # для Python, Shell и Ruby; используйте // для TypeScript, JavaScript, .mjs и Go. Маркер должен находиться в пределах первых 10 строк файла.

Поля такие:

  • provider — внешний сервис, с которым работает этот скрипт (например, google, stripe, openai). Именно по нему скрипт группируется на боковой панели.
  • service — необязательная подгруппа внутри провайдера (например, gmail, calendar). Если не указать, по умолчанию используется default.
  • name — необязательное отображаемое имя скрипта. По умолчанию используется имя файла.
  • description — необязательное однострочное описание.
  • requires — необязательный список того, что нужно скрипту для работы, в виде элементов kind:value (см. ниже).

Все поля необязательны, но на практике вам нужен provider, чтобы скрипт можно было сгруппировать. Частичный заголовок тоже подойдёт.

Пример для копирования (Python)

# @plank-integration
# provider: google
# service: gmail
# name: send_gmail
# description: Send a Gmail message.
# requires:
#   - cred: GOOGLE_API_KEY
#   - file: scripts/google/credentials.json

# … rest of your script

Пример для копирования (TypeScript)

Та же идея, но с комментариями //. Если вам удобнее уместить всё в одну строку, можно записать метаданные в виде JSON сразу после маркера:

// @plank-integration {"provider":"openai","service":"chat","requires":["cred:OPENAI_API_KEY"]}

Обе формы читаются одинаково. Используйте ту, которая вам удобнее.

Список requires

Каждый элемент — это строка kind:value, сообщающая Plank, от чего зависит скрипт:

  • cred:NAME — учётные данные, сохранённые под этим именем (например, cred:GOOGLE_API_KEY).
  • file:RELATIVE_PATH — файл, который должен быть на месте (например, file:scripts/google/credentials.json). Это не обязательно учётные данные: файл настроек, без которого скрипт не работает — скажем, file:scripts/1c/mapping.json, — указывается здесь же, и Plank проверяет его так же: ищет на диске.

Plank использует их, чтобы показать, полностью ли подключён провайдер или ему ещё чего-то не хватает. Виды элементов, которые он не распознаёт, просто игнорируются, так что опечатка не сломает скрипт.

Где хранятся учётные данные

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

  • OAuth-данные клиента → scripts/<provider>/credentials.json
  • OAuth-токены → scripts/<provider>/token.json, с полем expiry в формате ISO 8601 (и с refresh_token, который нужен SDK для самостоятельного обновления)

Именно это разделяет аккаунты: вы можете подключить личный Google-аккаунт в одном рабочем пространстве и рабочий — в другом, и ассистент никогда не подставит втихую токен из другого пространства, если в этом его нет, — он скажет, что токена нет. Это и есть та ошибка, которую стоит предотвращать: рабочее пространство действует от имени вашего личного аккаунта, а вы об этом не знаете.

Это правило, которому следует ассистент, а не стена внутри системы. Все ваши рабочие пространства открыты вам — и ассистенту, который работает от вашего имени. Поэтому прямо попросить его взять файл или запустить скрипт из другого вашего пространства — нормально, он должен просто сделать это и сказать, из какого пространства взял. Чего он не сделает — так это не полезет туда по своей инициативе.

Одно исключение, и оно намеренное: когда ассистента будит автоматизация — входящее сообщение в Telegram или WhatsApp, попавшее в веб-хук, — он остаётся внутри одного рабочего пространства. Рядом нет человека, который подтвердит действие, а написать в тот чат может кто угодно.

У личных и общих чатов разные домашние папки

Личный чат работает на вашей собственной машине, общий командный чат — на машине рабочего пространства. Оба видят одни и те же файлы рабочего пространства, но /home/coder у каждого свой. Вход через утилиту командной строки (большинство хранят логин в ~), pip install --user и всё остальное, что лежит в домашней папке одного вида чата, в другом не существует. Всё, что понадобится следующему чату, кладите в scripts/<provider>/ — это единственное место, которое видят оба.

Зависимости скрипта лежат рядом со скриптом

Если скрипту нужен Node-пакет, которого нет в образе, ставьте его в папку самого скрипта: npm install --prefix scripts/<provider> <пакет>. Так появятся scripts/<provider>/package.json и scripts/<provider>/node_modules в хранилище рабочего пространства — их видят все чаты, и они переживают пересоздание машины. (Python-пакеты из pip install --user лежат в домашней папке, поэтому в общем чате их, возможно, придётся поставить заново.)

Никогда не ставьте пакеты в .opencode/node_modules. Это собственное дерево плагинов ассистента из образа машины: всё добавленное туда существует только на одной машине и пропадает при её пересоздании, а .opencode/package.json перезаписывается при каждом запуске. Скрипт, импортировавший оттуда пакет, ломался дважды, прежде чем это поняли.

Токен, который уже лежит на месте, — это и есть подключение

Если в scripts/<provider>/ уже есть токен, интеграция подключена, пока реальный вызов не покажет обратное, — даже если вы в чате другого вида, чем тот, где её настраивали. Прежде чем авторизоваться заново, сделайте один недорогой запрос только на чтение. И никогда не перезаписывайте существующий файл токена в другом формате: его читают другие скрипты рабочего пространства, и если переписать его в том виде, который удобен вашему новому клиенту, они сломаются. Если второй токен действительно нужен, сохраните его под своим именем (например, token-<account>.json).

Если токен лежит в старом месте

Некоторые рабочие пространства были настроены до этого правила, и токен в них лежит за пределами scripts/ — обычно в /home/coder/.config/<provider>/<workspace>/token.json. Этот токен по-прежнему принадлежит этому рабочему пространству, по-прежнему работает, и правильнее всего продолжать использовать его там, где он лежит. Старое расположение — это не утечка и не отключённая интеграция.

Авторизация с нуля оправдана только тогда, когда провайдер отклоняет сами учётные данные: invalid_grant, отозванный доступ или 401, который остаётся после обновления токена. Ошибка 403 из-за квоты или прав, отключённый API или недостающие права у действующего доступа — это другие проблемы, и повторный вход их не решит. А если файла токена просто нет там, где вы ожидали, — сначала найдите путь, который скрипт действительно читает, а не делайте вывод, что всё сломалось.

Не переносите файл по своей инициативе. /home/coder приватен для одного пользователя, а рабочее пространство доступно всем, кого вы пригласили, — поэтому перенос учётных данных в scripts/ открывает доступ одного человека к Google (или 1С, или Stripe) всем участникам. В личном рабочем пространстве это безобидная уборка, в общем — неожиданность, о которой никто не просил. Если перенос нужен, скажите об этом, и ассистент сначала объяснит, что станет видно другим. Учтите, что такой путь лежит в приватной домашней папке одного человека, поэтому общий командный чат его не видит (см. выше) — там скажите, что токен недоступен, а не авторизуйтесь поверх него.

Боковая панель тоже учитывает старую схему: требование file:, записанное абсолютным путём (или через ~/…) внутри каталога ~/.config/<provider>/<workspace>/ этого же рабочего пространства, проверяется на диске именно там, куда указывает, поэтому интеграция показывается как подключённая, а не как неполная. Пути за пределами этого каталога намеренно не проверяются — иначе через заголовок скрипта можно было бы прощупывать приватные файлы другого участника.

Как скрипты группируются

Plank группирует каждый скрипт по его provider, а затем по service внутри него. Два скрипта, в которых указан provider: google, попадают в одну строку Google, даже если они лежат в разных папках. Имена провайдеров сопоставляются без учёта регистра, так что Google и google объединяются в одну строку.

Провайдер скрипта определяется двумя способами:

  1. Заголовок. Если у скрипта есть заголовок @plank-integration с указанным provider, побеждает он — и скрипт может находиться где угодно в рабочем пространстве.
  2. Путь к папке, только внутри scripts/. Если скрипт лежит по пути scripts/<provider>/<service>/… (например, scripts/google/gmail/send.py), Plank может определить провайдера и сервис по пути даже без заголовка.

Одиночный скрипт прямо в scripts/ (например, scripts/fetch.py) без заголовка не будет привязан — нет папки, из которой можно взять провайдера, поэтому добавьте заголовок. И в любом месте за пределами scripts/ заголовок обязателен: это и есть согласие, которое не даёт обычным файлам проекта (index.ts приложения, скрипту сборки) показываться как поддельные интеграции. Файлы конфигурации сборки и типов (такие как vite.config.ts или *.d.ts) никогда не считаются скриптами-интеграциями.

Надёжное правило, которое работает в любом случае: держите скрипты-интеграции в scripts/<provider>/<service>/ и добавляйте им заголовок. Процесс настройки у агента следует именно этому шаблону.

Запуск этих скриптов

Боковая панель отвечает за обнаружение и группировку — она показывает, какие интеграции существуют и подключены ли они. Сам запуск происходит в другом месте:

  • В чате. Нажатие на скрипт на боковой панели вставляет его путь в поле ввода чата, чтобы вы могли попросить агента запустить его.
  • С HTML-панели. Скрипт также может вывести кнопку на HTML-панели, чтобы пользователь мог запустить его одним нажатием. Это отдельное согласие — заголовок @plank-button, — описанное в разделе Интерактивные HTML-панели. Эти два заголовка независимы: скрипт может нести один из них, оба или ни одного.

Итак, @plank-integration решает, где появляется скрипт и с чем он соединяется; @plank-button решает, может ли панель запускать его напрямую.