feat(install): profile-based skill gating + public skills

- prompt for profile (frontend/backend/qa/mobile) via /dev/tty (works under curl|bash); PI_KIT_PROFILE env fallback
- gate bundled skills per profile by rewriting the pi-kit entry in settings.json to object-form {source, skills:[...]}; prompts/extensions stay ungated
- install common public skills for everyone (grill-me, grill-with-docs, code-review, diagnosing-bugs from mattpocock/skills) and profile-specific (frontend-design from anthropics/skills) via npx skills add --global
- README: profiles table + gating mechanism for maintainers

Verified: gating logic (string->object, idempotent, other packages preserved), live backend-profile load via RPC (ts excluded, prompts intact), npx skills add --global lands in ~/.agents/skills without cwd pollution, all 4 common skills exist in mattpocock/skills (diagnose is 'diagnosing-bugs').
This commit is contained in:
2026-07-16 12:15:07 +03:00
parent 7fc7d79815
commit fbf10b0521
2 changed files with 177 additions and 8 deletions

View File

@@ -16,11 +16,33 @@ guardrails и скиллы со знанием того, где у нас код
curl -fsSL https://git.codelab.vc/ai/pi-kit/-/raw/main/install.sh | bash curl -fsSL https://git.codelab.vc/ai/pi-kit/-/raw/main/install.sh | bash
``` ```
Скрипт проверит Node.js (>= 20), поставит Pi (если нет), установит этот пакет и подскажет, Скрипт проверит Node.js (>= 20), поставит Pi (если нет), установит этот пакет, **спросит
какие переменные окружения нужны (ключ вашего LLM-провайдера, `TRACKER_URL`, `JIRA_TOKEN`). твой профиль**, поставит нужные скилы и подскажет, какие переменные окружения нужны
(ключ вашего LLM-провайдера, `TRACKER_URL`, `JIRA_TOKEN`).
Pi провайдер-агностичен — модель/провайдера пакет не навязывает, каждый выбирает свой Pi провайдер-агностичен — модель/провайдера пакет не навязывает, каждый выбирает свой
(Anthropic, OpenAI, OpenRouter, …). (Anthropic, OpenAI, OpenRouter, …).
Профиль можно задать заранее (для CI/неинтерактивной установки):
```bash
PI_KIT_PROFILE=backend curl -fsSL https://git.codelab.vc/ai/pi-kit/-/raw/main/install.sh | bash
```
### Профили и скилы
Общее для всех: команды `/bugfix /feature /review /rfc /kit-config`, guardrails, скилы
`jira-workflow`, `repo-map`, `docs-map`, и публичные `grill-me`, `grill-with-docs`,
`code-review`, `diagnosing-bugs`. Дополнительно по профилю:
| Профиль | Языковые стандарты | Доп. публичные скилы |
|---|---|---|
| `frontend` | typescript | frontend-design |
| `backend` | go, rust, python | — |
| `qa` | python, typescript | — |
| `mobile` | — (TODO: kotlin/swift) | — |
Сменить профиль позже: `PI_KIT_PROFILE=frontend ./install.sh` (или перезапусти установку).
Либо вручную: Либо вручную:
```bash ```bash
@@ -125,6 +147,21 @@ pi-kit/
3. **Никаких секретов и URL в тексте** — только ссылки на корпоративный контекст сессии и 3. **Никаких секретов и URL в тексте** — только ссылки на корпоративный контекст сессии и
переменные окружения. переменные окружения.
### Профили и гейтинг скилов
`install.sh` спрашивает профиль (или берёт `PI_KIT_PROFILE`) и делает две вещи:
1. **Гейтит наши скилы** — переписывает запись пакета в `~/.pi/agent/settings.json` в
object-форму `{"source": "...", "skills": ["skills/go-standards", ...]}`, чтобы грузились
только скилы профиля. Prompts и расширения не гейтятся (их ключи опущены → грузятся все).
2. **Ставит публичные скилы** через `npx skills add <repo> --skill <name> --global` в
`~/.agents/skills/` (Pi читает эту папку). Чужой код в наш репо не вендорится.
Чтобы поменять маппинг профиль→скилы — правь блок `case "$PROFILE"` и `COMMON_PUBLIC_SKILLS`
в `install.sh`. Языковой скилл добавляется как обычный (см. ниже) и подключается к нужному
профилю в этом `case`. Профили: `frontend`, `backend`, `qa`, `mobile` (последний пока без
языковых стандартов — TODO kotlin/swift).
### Как добавить шаблон-команду ### Как добавить шаблон-команду
1. Создай `prompts/<name>.md` — имя файла станет командой `/<name>`. 1. Создай `prompts/<name>.md` — имя файла станет командой `/<name>`.

View File

@@ -7,6 +7,10 @@
# # or, from a checkout: # # or, from a checkout:
# ./install.sh # ./install.sh
# #
# Profile selection:
# Interactive by default (prompts via /dev/tty, so it works under curl | bash).
# Non-interactive: set PI_KIT_PROFILE=frontend|backend|qa|mobile before running.
#
set -euo pipefail set -euo pipefail
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -17,10 +21,19 @@ PI_KIT_REPO="git:git.codelab.vc/ai/pi-kit"
MIN_NODE_MAJOR=20 MIN_NODE_MAJOR=20
INTERNAL_COURSE_URL="TODO: ссылка на внутренний курс по Pi" INTERNAL_COURSE_URL="TODO: ссылка на внутренний курс по Pi"
SETTINGS="$HOME/.pi/agent/settings.json"
info() { printf '\033[1;34m==>\033[0m %s\n' "$*"; } # Public skills installed for EVERYONE (repo:skill), via `npx skills add`.
warn() { printf '\033[1;33m[!]\033[0m %s\n' "$*"; } COMMON_PUBLIC_SKILLS=(
err() { printf '\033[1;31m[x]\033[0m %s\n' "$*" >&2; } "mattpocock/skills:grill-me"
"mattpocock/skills:grill-with-docs"
"mattpocock/skills:code-review"
"mattpocock/skills:diagnosing-bugs" # диагностика багов (в mattpocock/skills скилл называется так)
)
info() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[!]\033[0m %s\n' "$*"; }
err() { printf '\033[1;31m[x]\033[0m %s\n' "$*" >&2; }
# --- 1. Node.js ------------------------------------------------------------- # --- 1. Node.js -------------------------------------------------------------
if ! command -v node >/dev/null 2>&1; then if ! command -v node >/dev/null 2>&1; then
@@ -56,7 +69,125 @@ info "Устанавливаю корпоративный пакет: ${PI_KIT_R
pi install "$PI_KIT_REPO" pi install "$PI_KIT_REPO"
info "Пакет установлен. Обновляться потом: pi update --extensions" info "Пакет установлен. Обновляться потом: pi update --extensions"
# --- 4. Provider API keys --------------------------------------------------- # --- 4. Resolve profile -----------------------------------------------------
# Precedence: PI_KIT_PROFILE env > interactive prompt > "all" (no gating).
PROFILE="${PI_KIT_PROFILE:-}"
case "$PROFILE" in
frontend | backend | qa | mobile) ;; # valid, keep
"") # ask if we have a terminal, even under `curl | bash` (read from /dev/tty)
if [ -r /dev/tty ]; then
{
printf 'Выбери профиль:\n'
printf ' 1) frontend — TS/UI\n'
printf ' 2) backend — Go/Rust/Python\n'
printf ' 3) qa — тестирование\n'
printf ' 4) mobile — Android/iOS\n'
printf 'Номер или имя [1-4]: '
} >/dev/tty
read -r ans </dev/tty || ans=""
case "$ans" in
1 | frontend) PROFILE=frontend ;;
2 | backend) PROFILE=backend ;;
3 | qa) PROFILE=qa ;;
4 | mobile) PROFILE=mobile ;;
*) PROFILE=all ;;
esac
else
PROFILE=all
fi
;;
*)
warn "Неизвестный PI_KIT_PROFILE='${PROFILE}', использую 'all' (без гейтинга скилов)."
PROFILE=all
;;
esac
info "Профиль: ${PROFILE}"
# Bundled language skills per profile. Common skills (jira-workflow/repo-map/
# docs-map) are always enabled. Prompts and guardrail extensions are never gated.
COMMON_BUNDLED="jira-workflow repo-map docs-map"
PROFILE_PUBLIC=()
case "$PROFILE" in
frontend)
LANG_BUNDLED="typescript-standards"
PROFILE_PUBLIC=("anthropics/skills:frontend-design")
;;
backend)
LANG_BUNDLED="go-standards rust-standards python-standards"
;;
qa) # TODO: уточнить стек тестировщиков; по умолчанию — Python и TS (автотесты)
LANG_BUNDLED="python-standards typescript-standards"
;;
mobile) # TODO: добавить kotlin-standards/swift-standards и мобильные скилы
LANG_BUNDLED=""
;;
*) # all: не гейтим, включаем все языковые скилы
LANG_BUNDLED="go-standards rust-standards python-standards typescript-standards"
;;
esac
# --- 5. Gate bundled skills via settings object-form filter -----------------
# Rewrites the pi-kit package entry in settings.json to {source, skills:[...]}
# so only the profile-relevant skills load. Extensions/prompts stay untouched
# (their keys are omitted => all load).
gate_bundled_skills() {
local allowed="$1"
if [ ! -f "$SETTINGS" ]; then
warn "settings.json не найден ($SETTINGS) — пропускаю гейтинг скилов."
return 0
fi
SETTINGS_FILE="$SETTINGS" ALLOWED="$allowed" SRC_MATCH="pi-kit" node <<'NODE'
const fs = require("fs");
const file = process.env.SETTINGS_FILE;
const allowed = process.env.ALLOWED.trim().split(/\s+/).filter(Boolean).map((s) => "skills/" + s);
const s = JSON.parse(fs.readFileSync(file, "utf8"));
if (!Array.isArray(s.packages)) process.exit(0);
let patched = false;
s.packages = s.packages.map((p) => {
const src = typeof p === "string" ? p : (p && p.source);
if (typeof src === "string" && src.includes(process.env.SRC_MATCH)) {
patched = true;
const base = (p && typeof p === "object") ? p : {};
return Object.assign({}, base, { source: src, skills: allowed });
}
return p;
});
fs.writeFileSync(file, JSON.stringify(s, null, 2) + "\n");
console.log(patched ? "gated bundled skills -> " + allowed.join(", ") : "pi-kit entry not found; skipped gating");
NODE
}
if [ "$PROFILE" = "all" ]; then
info "Профиль 'all' — оставляю все скилы пакета без гейтинга."
else
info "Гейчу скилы пакета под профиль '${PROFILE}'..."
gate_bundled_skills "${COMMON_BUNDLED} ${LANG_BUNDLED}" || warn "не удалось отфильтровать скилы (см. выше)."
fi
# --- 6. Install public skills ----------------------------------------------
# Uses the skills.sh CLI (`npx skills add`). Failures are non-fatal.
add_public_skill() { # <owner/repo> <skill-name>
local repo="$1" name="$2"
info "Публичный скилл: ${name} (${repo})"
# --global installs into ~/.agents/skills (the universal dir Pi reads),
# not the current project. --yes skips the interactive scope prompt.
if ! npx --yes skills add "https://github.com/${repo}" --skill "${name}" --global --yes >/dev/null 2>&1; then
warn "не удалось поставить '${name}'. Вручную: npx skills add https://github.com/${repo} --skill ${name} -g -y"
fi
}
info "Ставлю общие публичные скилы..."
for entry in "${COMMON_PUBLIC_SKILLS[@]}"; do
add_public_skill "${entry%%:*}" "${entry##*:}"
done
if [ "${#PROFILE_PUBLIC[@]}" -gt 0 ]; then
info "Ставлю публичные скилы профиля '${PROFILE}'..."
for entry in "${PROFILE_PUBLIC[@]}"; do
add_public_skill "${entry%%:*}" "${entry##*:}"
done
fi
# --- 7. Provider API keys ---------------------------------------------------
# Pi is provider-agnostic: engineers use different LLM providers (Anthropic, # Pi is provider-agnostic: engineers use different LLM providers (Anthropic,
# OpenAI, OpenRouter, Google, ...). The package does NOT pin a provider/model. # OpenAI, OpenRouter, Google, ...). The package does NOT pin a provider/model.
# We only check that *some* provider key is present and hint if none is. # We only check that *some* provider key is present and hint if none is.
@@ -86,14 +217,15 @@ else
EOF EOF
fi fi
# --- 5. Cheat sheet --------------------------------------------------------- # --- 8. Cheat sheet ---------------------------------------------------------
cat <<EOF cat <<EOF
──────────────────────────────────────────────────────── ────────────────────────────────────────────────────────
Готово! Памятка: Готово! Профиль: ${PROFILE}
Запуск: pi Запуск: pi
Обновление: pi update --extensions Обновление: pi update --extensions
Сменить профиль: PI_KIT_PROFILE=backend ./install.sh (или перезапусти и выбери)
Команды: /bugfix <тикет> /feature <тикет> Команды: /bugfix <тикет> /feature <тикет>
/review [фокус] /rfc <тема> /kit-config /review [фокус] /rfc <тема> /kit-config
Проверка: /kit-config — покажет действующие корпоративные значения Проверка: /kit-config — покажет действующие корпоративные значения