Skip to content
Back to skills

Pr

BSecurity

Provider-agnostic PR operations (GitHub / Bitbucket Server) for PM — create, list, view, diff, merge, comment, close, whoami. Use when PM mentions "open a PR", "create pull request", "push and open PR", "submit for review", "commit and open PR", "merge PR", "review PR status", "закоммить и сделай pr", "сделай пиар", "сделай pr", or any request to operate on GitHub / Bitbucket Server pull requests. Trigger liberally — skipping forces the agent to improvise with ad-hoc REST calls that bypass OP...

  • 7 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 5, 2026
ai-agentspythonshellbashgitapisecurity

Works with

  • cli
  • api

Security analysis

B75/100
  • criticalExfiltrates credentials via HTTP — exact pattern from Snyk ToxicSkills study

Pro shows the line behind each finding and how to fix it

Scanned September 22, 2026

npx -y skills add cryndoc/polisade-orchestrator --skill pr --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Pr?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Pr
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/cryndoc-polisade-orchestrator/badge)](https://www.skillsdirectory.com/skills/cryndoc-polisade-orchestrator)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: pr
description: 'Provider-agnostic PR operations (GitHub / Bitbucket Server) for PM — create, list, view, diff, merge, comment, close, whoami. Use when PM mentions "open a PR", "create pull request", "push and open PR", "submit for review", "commit and open PR", "merge PR", "review PR status", "закоммить и сделай pr", "сделай пиар", "сделай pr", or any request to operate on GitHub / Bitbucket Server pull requests. Trigger liberally — skipping forces the agent to improvise with ad-hoc REST calls that bypass OPS-028 push verification; over-triggering is recoverable (PM can redirect).'
argument-hint: <subcommand> [args]
---

# /polisade:pr — Provider-Agnostic PR Operations

Обёртка над `scripts/polisade_vcs.py` для ручных операций с PR: просмотр списка, диффа, комментарии, merge, close. Провайдер определяется из `.state/PROJECT_STATE.json → settings.vcsProvider` (`github` по умолчанию, `bitbucket-server` при корпоративном self-hosted Bitbucket).

Перед первым вызовом для Bitbucket заполни `.env` (BITBUCKET_DOMAIN1/2_URL + TOKEN) — подсказка в `env.example`, валидация через `/polisade:doctor`.

## Использование

```
/polisade:pr create --title T (--body B | --body-file F | --body-stdin) [--head BR] [--base main]
/polisade:pr list [--head BRANCH] [--state OPEN|MERGED|ALL]
/polisade:pr view <id>
/polisade:pr diff <id>
/polisade:pr merge <id> [--squash] [--delete-branch]
/polisade:pr comment <id> (--body T | --body-file F | --body-stdin)
/polisade:pr close <id>
/polisade:pr whoami
```

<!-- polisade:exec-denied CAPSULE BEGIN -->
> ⛔ **Вызов скрипта отклонён или не запустился** (`Command references protected path` / `Install directory is read-protected` / `Filesystem Guard` / `the tool's default permission is 'deny'`, отказ песочницы, ненулевой exit без вывода) — **STOP**.
> Процитируй отказ дословно. НЕ пересказывай по исходнику, что скрипт «сделал бы»; НЕ собирай dry-run вручную; НЕ переходи к apply/push/pr-create.
> НЕ транскрибируй скрипт (прочитать → записать копию в `/tmp` или в проект → запустить копию): копия не байт-идентична — уезжают классы символов в regex, форма возврата функций, пропадают целые функции — и молча меняется набор применённых изменений.
> Отказ инструмента — это отказ, а не результат. Доложи PM дословный текст отказа и сошлись на #127 (доставка скриптов в проект).
<!-- polisade:exec-denied CAPSULE END -->

Имена параметров соответствуют argparse в `scripts/polisade_vcs.py` — единственный source of truth. Проверь: `${POLISADE_PYTHON:-python3} {plugin_root}/scripts/polisade_vcs.py --help`.

## Алгоритм

1. Распарсить `$ARGUMENTS` как `<subcommand> [args]`.
2. Смаппить короткую форму субкоманды на имя скрипта:

   ```
   create  → pr-create
   list    → pr-list
   view    → pr-view
   diff    → pr-diff
   merge   → pr-merge
   comment → pr-comment
   close   → pr-close
   whoami  → whoami           (остаётся как есть)
   ```

3. Определить `WORK_DIR = ${POLISADE_WORK_DIR:-.}` — если вызов из worktree, скрипт должен читать локальный `.state/PROJECT_STATE.json` и `.env`. Caller (агент) обязан заранее `cd` в нужный каталог; статический fallback `.` намеренно не использует command substitution — корп-шелл (GigaCode CLI / codex sandbox) режет `$()` (см. anti-patterns ниже).
4. Выполнить:

<!-- polisade:exec-denied CAPSULE BEGIN -->
> ⛔ **Вызов скрипта отклонён или не запустился** (`Command references protected path` / `Install directory is read-protected` / `Filesystem Guard` / `the tool's default permission is 'deny'`, отказ песочницы, ненулевой exit без вывода) — **STOP**.
> Процитируй отказ дословно. НЕ пересказывай по исходнику, что скрипт «сделал бы»; НЕ собирай dry-run вручную; НЕ переходи к apply/push/pr-create.
> НЕ транскрибируй скрипт (прочитать → записать копию в `/tmp` или в проект → запустить копию): копия не байт-идентична — уезжают классы символов в regex, форма возврата функций, пропадают целые функции — и молча меняется набор применённых изменений.
> Отказ инструмента — это отказ, а не результат. Доложи PM дословный текст отказа и сошлись на #127 (доставка скриптов в проект).
<!-- polisade:exec-denied CAPSULE END -->
<!-- polisade:push-stop CAPSULE BEGIN -->
> ⛔ **`polisade_vcs.py` недоступен** (`Command references protected path` / `Install directory is read-protected` / `Filesystem Guard`) — **STOP до push**: ни `git-push`, ни `pr-create`, ни `pr-merge`, ни `pr-comment` не выполняются.
> Bare `git push` запрещён (инвариант #10 / OPS-028); самодельные REST/curl-вызовы к Bitbucket/GitHub запрещены; helper не транскрибируется в `/tmp`.
> Доложи PM дословно: «push пропущен — `polisade_vcs.py` заблокирован sandbox (#127); коммит локально в ветке `<имя>`; pr-create не выполнялся» — и заверши рецепт на этом.
<!-- polisade:push-stop CAPSULE END -->

```bash
${POLISADE_PYTHON:-python3} {plugin_root}/scripts/polisade_vcs.py <script-cmd> <args> \
  --project-root "${POLISADE_WORK_DIR:-.}"
```

5. Человекочитаемо отформатировать результат:
   - `create` → номер + URL + head branch. **Поле `existing` (issue #158):**
     `pr-create` идемпотентен — если по head-ветке уже открыт PR, скрипт
     возвращает ЕГО в том же JSON-контракте с `existing: true` и exit 0,
     вместо того чтобы открыть дубль. Свежесозданный PR приходит с
     `existing: false`. Различай в отчёте PM («PR уже открыт: #N» vs «PR
     создан: #N») — молча выдать чужой номер за свежий значит соврать.
     Идемпотентность считает только ОТКРЫТЫЕ PR: смерженный или закрытый PR
     на той же ветке созданию не мешает.
   - `list` → таблица (number, head, state).
   - `view` → ключевые поля + URL.
   - `diff` → stdout как есть (уже text).
   - `merge` / `close` / `comment` — краткая сводка (`#N <state>`, `branch_deleted: yes/no`, warnings если есть).
   - `whoami` — инстанс и провайдер.
6. На non-zero exit показать stderr + подсказку: `запусти /polisade:doctor для диагностики VCS`.

## Частые ошибки

<!-- polisade:exec-denied CAPSULE BEGIN -->
> ⛔ **Вызов скрипта отклонён или не запустился** (`Command references protected path` / `Install directory is read-protected` / `Filesystem Guard` / `the tool's default permission is 'deny'`, отказ песочницы, ненулевой exit без вывода) — **STOP**.
> Процитируй отказ дословно. НЕ пересказывай по исходнику, что скрипт «сделал бы»; НЕ собирай dry-run вручную; НЕ переходи к apply/push/pr-create.
> НЕ транскрибируй скрипт (прочитать → записать копию в `/tmp` или в проект → запустить копию): копия не байт-идентична — уезжают классы символов в regex, форма возврата функций, пропадают целые функции — и молча меняется набор применённых изменений.
> Отказ инструмента — это отказ, а не результат. Доложи PM дословный текст отказа и сошлись на #127 (доставка скриптов в проект).
<!-- polisade:exec-denied CAPSULE END -->
<!-- polisade:push-stop CAPSULE BEGIN -->
> ⛔ **`polisade_vcs.py` недоступен** (`Command references protected path` / `Install directory is read-protected` / `Filesystem Guard`) — **STOP до push**: ни `git-push`, ни `pr-create`, ни `pr-merge`, ни `pr-comment` не выполняются.
> Bare `git push` запрещён (инвариант #10 / OPS-028); самодельные REST/curl-вызовы к Bitbucket/GitHub запрещены; helper не транскрибируется в `/tmp`.
> Доложи PM дословно: «push пропущен — `polisade_vcs.py` заблокирован sandbox (#127); коммит локально в ветке `<имя>`; pr-create не выполнялся» — и заверши рецепт на этом.
<!-- polisade:push-stop CAPSULE END -->

- ❌ `polisade_vcs.py create` — подкоманда называется `pr-create` (префикс `pr-` обязателен для всех PR-операций кроме `whoami`).
- ❌ `--source-branch` / `--target-branch` / `--description` — это GitHub REST API; наш скрипт принимает `--head` / `--base` / `--body` (см. `--help`).
- ❌ Однострочный `--body "..."` с кавычками внутри текста → ломает shell quoting. Для многострочных тел используй `--body-file .polisade/tmp/body.md` или `--body-stdin`. `/tmp` НЕ используется: GigaCode CLI sandboxes /tmp, и файл становится невидим последующему `--body-file` (issue #57; project-local `.polisade/tmp/` — в `.gitignore`).
- ⛔ NEVER `--body "$(git log -1 --pretty=%B)"` / `--body \`...\`` / `--body <(...)` / `--body >(...)` — корп-шелл (GigaCode CLI, codex sandbox) режет любую command substitution с сообщением «Command substitution using $(), \`\`, <(), or >() is not allowed for security reasons». Запрет шире, чем уже декларированный «однострочный --body с кавычками»: тут нельзя сам shell-construct, не только многострочное body. Канонический путь — файл: `git log -1 --pretty=%B > .polisade/tmp/pr-body.md && /polisade:pr create --body-file .polisade/tmp/pr-body.md ...`. Issue #108 / OPS-057.
- ⛔ NEVER самодельный Python/curl в Bitbucket/GitHub REST API: `requests.post(".../pull-requests", json=...)`, чтение `BITBUCKET_DOMAIN1_TOKEN` / `BITBUCKET_DOMAIN2_TOKEN` через `subprocess` или `os.environ`, прямой `curl -X POST` к API. Это weak-model footgun: токены утекают мимо `polisade_vcs.py`, теряется OPS-028 push verification, теряется provider-agnostic мост (GitHub vs Bitbucket Server vs корпоративный фронт). Любой PR-flow проходит через `${POLISADE_PYTHON:-python3} {plugin_root}/scripts/polisade_vcs.py pr-create ...` — даже когда «всё равно нужно одну строчку отправить». Issue #108 (PM в корп-сессии отменил такой ad-hoc subprocess вручную).
- ⛔ NEVER `polisade_pr.py` / `${POLISADE_PYTHON:-python3} scripts/polisade_pr.py` — такого файла НЕ существует. Канонический скрипт — `scripts/polisade_vcs.py` с подкомандами `pr-create / pr-list / pr-view / pr-diff / pr-merge / pr-comment / pr-close / whoami`. Source-of-truth list — `${POLISADE_PYTHON:-python3} {plugin_root}/scripts/polisade_vcs.py --help`. Эта путаница `/polisade:pr ↔ polisade_pr.py` — тоже регрессия из issue #108: weak-model агент пробовал угадать имя файла из имени слаш-команды.

Source of truth для имён subparser'ов и параметров: `${POLISADE_PYTHON:-python3} {plugin_root}/scripts/polisade_vcs.py --help`.

## Важно

- **Merge собственных PR, созданных в автоцикле, делает PM** — автоматические merge происходят только в `/polisade:continue` после успешного review.
- **Close / decline** безвозвратно закрывает PR (Bitbucket: переводит в `DECLINED`, GitHub: `CLOSED`).
- Длинные тела для `comment` / `create` удобнее передавать через `--body-file`, а не `--body "..."` — кавычки внутри текста ломают quoting.
- ⛔ NEVER `git add -f <path>` / `git add --force <path>` перед `/polisade:pr create`
  на путях, которые в `.gitignore` (`.gigacode/`, `.qwen/`, `.codex/`,
  `.worktrees/` и т.п.). `/polisade:pr` сам `git add` не выполняет, но если PM
  перед вызовом собрал коммит с force-add'ом gitignored-пути, это тот же
  weak-model footgun (issue #74). Полные правила — в `## Git Safety` в
  `CLAUDE.md` target-проекта и в `skills/implement/SKILL.md`.

### Пример: создать PR с многострочным body

```bash
mkdir -p .polisade/tmp
cat > .polisade/tmp/pr-body.md <<'EOF'
## Summary
Fixes TASK-X.

## Tests
- pytest tests/foo -k new_case
EOF
/polisade:pr create --title "[TASK-X] Foo bug" --body-file .polisade/tmp/pr-body.md --head feat/TASK-X
```

## Настройка Bitbucket Server

См. раздел «VCS providers» в `CLAUDE.md`. Короткая версия:

1. `/polisade:init` или `/polisade:migrate --apply` создаст `.env` (stub) и `.env.example` из plugin templates.
2. Заполни в `.env` хотя бы один домен: `BITBUCKET_DOMAIN1_URL` + `BITBUCKET_DOMAIN1_TOKEN` (auth_type `bearer` по умолчанию; `basic` — при 401).
3. `/polisade:pr whoami` — проверка что токен валиден и инстанс выбран правильно.
4. `/polisade:doctor --vcs` — полная диагностика.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.