media-upload
**UNIVERSAL TRIGGER**: Use when user wants to UPLOAD/SAVE/ATTACH/SHARE images or media files to S3. **AUTO-TRIGGER**: Activate AUTOMATICALLY after taking screenshots with Playwright MCP. Common patterns: - "upload/save/attach/share [file] to s3" - "get/fetch public link for [image]" - "show/list/display recent uploads" - "сделай скриншот и сохрани" (screenshot + upload) - "открой сайт и сделай скриншот" (implies upload) **Screenshots** (AUTO-ACTIVATE after Playwright screenshot): - After `browser_take_screenshot` → automatically offer to upload - "upload screenshot", "save screenshot", "attach screenshot" - "загрузи скриншот", "приложи скриншот", "сохрани скриншот" - "сделай скриншот [сайта]" → take screenshot + upload to S3 ️ **Images**: - "upload/save/attach image/picture/photo" - "share png/jpg/gif", "get link for image" **Batch**: - "upload all png from ./folder/" - "загрузи все картинки" **History**: - "show/list recent uploads" - "покажи загрузки" TRIGGERS: upload, save, attach, share, get link, show uploads, list uploads, screenshot, image, picture, photo, png, jpg, gif, webp, svg, pdf, s3, bucket, cdn, minio, public link, скриншот, картинка, загрузи, сохрани, сделай скриншот, take screenshot, browser_take_screenshot, playwright screenshot
Best use case
media-upload is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
**UNIVERSAL TRIGGER**: Use when user wants to UPLOAD/SAVE/ATTACH/SHARE images or media files to S3. **AUTO-TRIGGER**: Activate AUTOMATICALLY after taking screenshots with Playwright MCP. Common patterns: - "upload/save/attach/share [file] to s3" - "get/fetch public link for [image]" - "show/list/display recent uploads" - "сделай скриншот и сохрани" (screenshot + upload) - "открой сайт и сделай скриншот" (implies upload) **Screenshots** (AUTO-ACTIVATE after Playwright screenshot): - After `browser_take_screenshot` → automatically offer to upload - "upload screenshot", "save screenshot", "attach screenshot" - "загрузи скриншот", "приложи скриншот", "сохрани скриншот" - "сделай скриншот [сайта]" → take screenshot + upload to S3 ️ **Images**: - "upload/save/attach image/picture/photo" - "share png/jpg/gif", "get link for image" **Batch**: - "upload all png from ./folder/" - "загрузи все картинки" **History**: - "show/list recent uploads" - "покажи загрузки" TRIGGERS: upload, save, attach, share, get link, show uploads, list uploads, screenshot, image, picture, photo, png, jpg, gif, webp, svg, pdf, s3, bucket, cdn, minio, public link, скриншот, картинка, загрузи, сохрани, сделай скриншот, take screenshot, browser_take_screenshot, playwright screenshot
Teams using media-upload should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/media-upload/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How media-upload Compares
| Feature / Agent | media-upload | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
**UNIVERSAL TRIGGER**: Use when user wants to UPLOAD/SAVE/ATTACH/SHARE images or media files to S3. **AUTO-TRIGGER**: Activate AUTOMATICALLY after taking screenshots with Playwright MCP. Common patterns: - "upload/save/attach/share [file] to s3" - "get/fetch public link for [image]" - "show/list/display recent uploads" - "сделай скриншот и сохрани" (screenshot + upload) - "открой сайт и сделай скриншот" (implies upload) **Screenshots** (AUTO-ACTIVATE after Playwright screenshot): - After `browser_take_screenshot` → automatically offer to upload - "upload screenshot", "save screenshot", "attach screenshot" - "загрузи скриншот", "приложи скриншот", "сохрани скриншот" - "сделай скриншот [сайта]" → take screenshot + upload to S3 ️ **Images**: - "upload/save/attach image/picture/photo" - "share png/jpg/gif", "get link for image" **Batch**: - "upload all png from ./folder/" - "загрузи все картинки" **History**: - "show/list recent uploads" - "покажи загрузки" TRIGGERS: upload, save, attach, share, get link, show uploads, list uploads, screenshot, image, picture, photo, png, jpg, gif, webp, svg, pdf, s3, bucket, cdn, minio, public link, скриншот, картинка, загрузи, сохрани, сделай скриншот, take screenshot, browser_take_screenshot, playwright screenshot
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Media Upload Skill
Загрузка изображений и медиафайлов в S3-совместимое хранилище через `mc` (MinIO Client) с получением публичной ссылки.
## ⚠️ CRITICAL: Приоритет URL
**ОБЯЗАТЕЛЬНО** после загрузки файла:
1. Если в конфиге есть `public_url` и `url_mode` НЕ равен `"presigned"`:
- **СРАЗУ** возвращай короткий CDN URL: `${public_url}/${remote_path}`
- **НЕ генерируй** presigned URL
2. Только если `url_mode: "presigned"` или `public_url` отсутствует:
- Генерируй presigned URL через `mc share download`
**Пример правильного поведения:**
```
Конфиг: { "public_url": "https://cdn.example.com", "url_mode": "public" }
Путь: 2026/02/03/screenshot.png
→ Возвращай: https://cdn.example.com/2026/02/03/screenshot.png
→ НЕ возвращай: https://s3...?X-Amz-Algorithm=...
```
## Поддерживаемые форматы
| Тип | Расширения | MIME-type |
|-----|------------|-----------|
| Изображения | png, jpg, jpeg, gif, webp, svg | image/* |
| Документы | pdf | application/pdf |
| Видео | mp4, webm (будущее) | video/* |
## Приоритет определения источника файла
1. **Явный путь** — пользователь указал `/path/to/file.png` в запросе
2. **Playwright MCP** — последний результат `browser_take_screenshot` в текущей сессии
3. **Glob паттерн** — "загрузи все png из ./screenshots/"
4. **Спросить пользователя** — если ничего не найдено
### Интеграция с Playwright MCP
**ВАЖНО**: Этот скилл должен активироваться АВТОМАТИЧЕСКИ после создания скриншота через Playwright MCP.
#### Паттерны запросов пользователя
Когда пользователь просит:
- "открой сайт X и сделай скриншот"
- "сделай скриншот страницы Y"
- "take a screenshot of Z"
**Алгоритм**:
1. Загрузить инструменты Playwright MCP через ToolSearch
2. Открыть браузер и перейти на страницу (`browser_navigate`)
3. Сделать скриншот (`browser_take_screenshot`)
4. **АВТОМАТИЧЕСКИ** загрузить скриншот в S3 (этот скилл)
5. Вернуть пользователю публичную ссылку
#### Формат ответа Playwright
Playwright MCP при вызове `browser_take_screenshot` возвращает:
```
Took the viewport screenshot and saved it as /tmp/page-2024-01-31-143052.png
```
Парси этот формат регулярным выражением:
```bash
SCREENSHOT_PATH=$(echo "$PLAYWRIGHT_OUTPUT" | grep -oP 'saved it as \K/[^\s]+\.png')
```
#### Пример полного флоу
```
User: "открой kiiiosk.store и сделай скриншот"
1. ToolSearch: load playwright tools
2. browser_navigate: https://kiiiosk.store
3. browser_take_screenshot → /tmp/page-2026-02-01-123456.png
4. media-upload skill activates automatically
5. MC_REGION=ru-3 mc cp --insecure /tmp/page-... screenshots/claude-screenshots/2026/02/01/...
6. Return: "✅ Screenshot uploaded: https://..."
```
## Конфигурация
### Файл конфигурации
**Путь**: `~/.config/claude-code/media-upload.json`
**С CDN (рекомендуется):**
```json
{
"mc_path": "screenshots/claude-screenshots",
"public_url": "https://cdn.example.com",
"url_mode": "public",
"organize_by": "date",
"max_file_size_mb": 100
}
```
**Без CDN (только presigned):**
```json
{
"mc_path": "screenshots/claude-screenshots",
"url_mode": "presigned",
"presigned_expire": "168h",
"organize_by": "date",
"max_file_size_mb": 100
}
```
**Примечание**: Если есть `public_url`, используй `url_mode: "public"` для коротких постоянных ссылок.
### Режимы URL (`url_mode`)
| Режим | Описание |
|-------|----------|
| `public` | Использовать публичный URL (требует CDN домен, не S3 API) |
| `presigned` | **Рекомендуется для Selectel**. Генерировать presigned URL через `mc share` |
| `auto` | Проверить публичный доступ, fallback на presigned |
**`presigned_expire`** — время жизни presigned URL (по умолчанию `168h` = 7 дней, **максимум** для mc)
**⚠️ ВАЖНО для Selectel Cloud Storage:**
- S3 API Selectel **НЕ поддерживает анонимный доступ** — все запросы должны быть подписаны
- Настройка "Публичный" в консоли Selectel работает **только через домен `selstorage.ru`**, не через S3 API
- Для S3-совместимого доступа используйте `presigned` режим
### Переменные окружения (высший приоритет)
```bash
MEDIA_UPLOAD_MC_PATH=screenshots/claude-screenshots
MEDIA_UPLOAD_PUBLIC_URL=https://s3.ru-3.storage.selcloud.ru/claude-screenshots
MEDIA_UPLOAD_ORGANIZE_BY=date
MEDIA_UPLOAD_MAX_FILE_SIZE_MB=100
MEDIA_UPLOAD_HISTORY_FILE=~/.media-upload-history.json
MEDIA_UPLOAD_URL_MODE=auto
MEDIA_UPLOAD_PRESIGNED_EXPIRE=168h
```
**Приоритет конфигурации**: Environment variables > JSON config > Default values
### Организация файлов в S3
```bash
# organize_by: "date" (по умолчанию)
screenshots/2024/01/31/screenshot-2024-01-31-143052.png
# organize_by: "type"
screenshots/images/screenshot-2024-01-31-143052.png
screenshots/documents/report.pdf
# organize_by: "flat"
screenshots/screenshot-2024-01-31-143052.png
```
## Security
### Credentials
- Credentials хранятся **только** в `mc alias` (настраивается через `mc alias set`)
- **Никогда** не хранить access/secret keys в `media-upload.json`
- Минимальные IAM права для mc alias: `PutObject` на конкретный bucket
### Валидация файлов
- Проверка magic bytes файла (соответствие расширению)
- Санитизация имени файла: удаление `../`, замена спецсимволов
- Пример: `my screenshot (1).png` → `my-screenshot-1.png`
### Права доступа
- Config файлы создаются с правами 600 (только владелец)
## Лимиты размера файлов
| Порог | Действие |
|-------|----------|
| > 10 MB | Warning: показать размер |
| > 50 MB | Confirmation: запросить подтверждение |
| > 100 MB | Block: отказать (настраивается в конфигурации) |
## mc CLI Contract
### Selectel Cloud Storage: Обязательные настройки
**⚠️ КРИТИЧЕСКИ ВАЖНО для Selectel:**
MinIO Client по умолчанию использует `eu-central-1` в подписи, а Selectel требует `ru-3`.
**Вариант 1: Добавить регион в конфиг mc (рекомендуется)**
```bash
# Добавить регион в существующий alias через jq
jq '.aliases.screenshots.region = "ru-3"' ~/.mc/config.json > /tmp/mc-config.json && \
mv /tmp/mc-config.json ~/.mc/config.json
```
**Вариант 2: Через переменную окружения**
```bash
export MC_REGION=ru-3
mc cp LOCAL_FILE ALIAS/BUCKET/PATH
```
**SSL проблемы**: Если есть ошибки SSL certificate, использовать `--insecure`:
```bash
mc cp --insecure LOCAL_FILE ALIAS/BUCKET/PATH
```
### Используемые команды
```bash
# Проверка алиаса
mc alias list | grep ALIAS_NAME
# Загрузка файла (Selectel)
MC_REGION=ru-3 mc cp LOCAL_FILE ALIAS/BUCKET/PATH
# Загрузка файла (Selectel с SSL проблемами)
MC_REGION=ru-3 mc cp --insecure LOCAL_FILE ALIAS/BUCKET/PATH
# Проверка соединения (Setup Wizard)
MC_REGION=ru-3 mc ls ALIAS/BUCKET --limit 1
```
### Exit codes
- `0` — успех
- `1` — ошибка (детали в stderr)
## Алгоритм загрузки
### Шаг 1: Проверка конфигурации
```bash
# Проверить наличие конфигурации
CONFIG_FILE="$HOME/.config/claude-code/media-upload.json"
if [[ ! -f "$CONFIG_FILE" ]]; then
# Запустить Setup Wizard
fi
```
### Шаг 2: Чтение конфигурации
```bash
# Проверить наличие jq
if ! command -v jq &> /dev/null; then
echo "❌ jq не установлен (требуется для чтения конфигурации)"
echo "Установка: brew install jq / apt install jq"
exit 1
fi
# Проверить валидность JSON
if ! jq empty "$CONFIG_FILE" 2>/dev/null; then
echo "❌ Невалидный JSON в $CONFIG_FILE"
exit 1
fi
# Приоритет: ENV > JSON > defaults
MC_PATH="${MEDIA_UPLOAD_MC_PATH:-$(jq -r '.mc_path // empty' "$CONFIG_FILE")}"
PUBLIC_URL="${MEDIA_UPLOAD_PUBLIC_URL:-$(jq -r '.public_url // empty' "$CONFIG_FILE")}"
ORGANIZE_BY="${MEDIA_UPLOAD_ORGANIZE_BY:-$(jq -r '.organize_by // "date"' "$CONFIG_FILE")}"
MAX_SIZE="${MEDIA_UPLOAD_MAX_FILE_SIZE_MB:-$(jq -r '.max_file_size_mb // 100' "$CONFIG_FILE")}"
# Проверить обязательные поля
if [[ -z "$MC_PATH" ]]; then
echo "❌ mc_path не задан в конфигурации"
exit 1
fi
# public_url необязателен для режима presigned
```
### Шаг 3: Валидация файла
```bash
# Проверить существование и доступность
if [[ ! -f "$FILE" ]] || [[ ! -r "$FILE" ]]; then
echo "❌ Файл не найден или недоступен для чтения: $FILE"
exit 1
fi
# Проверить пустой файл
if [[ ! -s "$FILE" ]]; then
echo "❌ Файл пустой, загрузка отменена"
exit 1
fi
# Получить размер файла (кроссплатформенно)
if ! SIZE_BYTES=$(stat -f%z "$FILE" 2>/dev/null || stat -c%s "$FILE" 2>/dev/null); then
echo "❌ Не удалось получить размер файла: $FILE"
exit 1
fi
if ! [[ "$SIZE_BYTES" =~ ^[0-9]+$ ]]; then
echo "❌ Ошибка определения размера файла: $FILE"
exit 1
fi
SIZE_MB=$(( SIZE_BYTES / 1048576 ))
if [[ $SIZE_MB -gt $MAX_SIZE ]]; then
echo "❌ Файл слишком большой: ${SIZE_MB}MB > ${MAX_SIZE}MB"
exit 1
fi
```
### Шаг 4: Санитизация имени файла
```bash
sanitize_filename() {
local filename="$1"
# Удалить путь, оставить только имя
filename="${filename##*/}"
# Заменить пробелы и спецсимволы на дефисы
filename=$(echo "$filename" | sed 's/[^a-zA-Z0-9._-]/-/g' | sed 's/--*/-/g' | sed 's/-$//')
echo "$filename"
}
```
### Шаг 5: Формирование пути в S3
```bash
EXT="${FILE##*.}"
DATE_PATH=$(date +%Y/%m/%d)
SANITIZED_NAME=$(sanitize_filename "$FILE")
case "$ORGANIZE_BY" in
date) REMOTE_PATH="${DATE_PATH}/${SANITIZED_NAME}" ;;
type)
# Определить тип по расширению
case "${EXT,,}" in
pdf) TYPE_DIR="documents" ;;
png|jpg|jpeg|gif|webp|svg) TYPE_DIR="images" ;;
mp4|webm) TYPE_DIR="videos" ;;
*) TYPE_DIR="other" ;;
esac
REMOTE_PATH="${TYPE_DIR}/${SANITIZED_NAME}"
;;
flat) REMOTE_PATH="${SANITIZED_NAME}" ;;
esac
```
### Шаг 6: Загрузка через mc
```bash
# Проверить наличие региона в конфиге mc
MC_ALIAS=$(echo "$MC_PATH" | cut -d'/' -f1)
MC_HAS_REGION=$(jq -r ".aliases.${MC_ALIAS}.region // empty" ~/.mc/config.json 2>/dev/null)
# Если региона нет в конфиге, попробовать добавить (для Selectel)
if [[ -z "$MC_HAS_REGION" ]] && [[ "$MC_ALIAS" == "screenshots" ]]; then
# Добавить регион ru-3 для Selectel
jq ".aliases.${MC_ALIAS}.region = \"ru-3\"" ~/.mc/config.json > /tmp/mc-config.json && \
mv /tmp/mc-config.json ~/.mc/config.json
echo "ℹ️ Добавлен регион ru-3 в конфиг mc для Selectel"
fi
# Захватить stderr для диагностики
MC_OUTPUT=$(mc cp "$FILE" "${MC_PATH}/${REMOTE_PATH}" 2>&1)
MC_EXIT=$?
# Если ошибка региона - попробовать с MC_REGION
if [[ $MC_EXIT -ne 0 ]] && echo "$MC_OUTPUT" | grep -q "region.*wrong"; then
echo "ℹ️ Повторная попытка с MC_REGION=ru-3"
MC_OUTPUT=$(MC_REGION=ru-3 mc cp "$FILE" "${MC_PATH}/${REMOTE_PATH}" 2>&1)
MC_EXIT=$?
fi
# Если SSL ошибка - попробовать с --insecure
if [[ $MC_EXIT -ne 0 ]] && echo "$MC_OUTPUT" | grep -qi "ssl\|certificate"; then
echo "ℹ️ Повторная попытка с --insecure"
MC_OUTPUT=$(mc cp --insecure "$FILE" "${MC_PATH}/${REMOTE_PATH}" 2>&1)
MC_EXIT=$?
fi
if [[ $MC_EXIT -ne 0 ]]; then
echo "❌ Ошибка загрузки файла: $FILE"
echo ""
echo "Детали ошибки:"
echo "$MC_OUTPUT"
exit 1
fi
```
### Шаг 6.1: Генерация URL
```bash
URL_MODE="${MEDIA_UPLOAD_URL_MODE:-$(jq -r '.url_mode // "auto"' "$CONFIG_FILE")}"
PRESIGNED_EXPIRE="${MEDIA_UPLOAD_PRESIGNED_EXPIRE:-$(jq -r '.presigned_expire // "168h"' "$CONFIG_FILE")}"
generate_url() {
local remote_path="$1"
local public_url_full="${PUBLIC_URL}/${remote_path}"
case "$URL_MODE" in
public)
echo "$public_url_full"
;;
presigned)
# Генерировать presigned URL
mc share download --expire="$PRESIGNED_EXPIRE" "${MC_PATH}/${remote_path}" 2>&1 | \
grep "^Share:" | cut -d' ' -f2
;;
auto|*)
# Проверить публичный доступ
HTTP_CODE=$(curl -sI -o /dev/null -w "%{http_code}" "$public_url_full" 2>/dev/null || echo "000")
if [[ "$HTTP_CODE" == "200" ]]; then
echo "$public_url_full"
else
# Fallback на presigned
mc share download --expire="$PRESIGNED_EXPIRE" "${MC_PATH}/${remote_path}" 2>&1 | \
grep "^Share:" | cut -d' ' -f2
fi
;;
esac
}
PUBLIC_URL_FULL=$(generate_url "$REMOTE_PATH")
```
### Шаг 7: Запись в историю
```bash
# Получить путь к файлу истории (ENV > JSON config > default)
HISTORY_FILE="${MEDIA_UPLOAD_HISTORY_FILE:-$(jq -r '.history_file // empty' "$CONFIG_FILE" 2>/dev/null | sed "s|~|$HOME|")}"
HISTORY_FILE="${HISTORY_FILE:-$HOME/.media-upload-history.json}"
# Создать файл если не существует
if [[ ! -f "$HISTORY_FILE" ]]; then
echo '{"uploads":[]}' > "$HISTORY_FILE"
chmod 600 "$HISTORY_FILE"
fi
# Добавить запись (через jq)
# SIZE_BYTES определен в Шаге 3
if ! jq --arg file "$FILE" \
--arg url "$PUBLIC_URL_FULL" \
--arg size "$SIZE_BYTES" \
--arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'.uploads += [{"file":$file,"url":$url,"size":($size|tonumber),"timestamp":$ts}]' \
"$HISTORY_FILE" > "${HISTORY_FILE}.tmp"; then
echo "⚠️ Загрузка успешна, но запись в историю не удалась"
rm -f "${HISTORY_FILE}.tmp"
elif ! mv "${HISTORY_FILE}.tmp" "$HISTORY_FILE"; then
echo "⚠️ Не удалось сохранить историю: ошибка перемещения файла"
rm -f "${HISTORY_FILE}.tmp"
fi
```
## Setup Wizard (первый запуск)
**Условие запуска**:
- Отсутствует файл `~/.config/claude-code/media-upload.json`
- ИЛИ отсутствуют обязательные поля: `mc_path`, `public_url`
### Процесс
1. Проверить установку mc:
```bash
if ! command -v mc &> /dev/null; then
echo "❌ mc не установлен"
echo "Установка:"
echo " macOS: brew install minio-mc"
echo " Linux: apt install minio-mc"
exit 1
fi
echo "✅ mc is installed"
```
2. Запросить параметры через AskUserQuestion:
- `mc_path` (alias/bucket): например `screenshots/screenshots`
- `public_url`: например `https://cdn.example.com/screenshots`
3. Проверить соединение:
```bash
mc ls "${MC_PATH}" --limit 1
if [[ $? -ne 0 ]]; then
echo "❌ Не удалось подключиться к ${MC_PATH}"
echo "Проверьте настройку alias: mc alias set ..."
exit 1
fi
echo "✅ Bucket accessible"
```
4. Сохранить конфигурацию:
```bash
mkdir -p ~/.config/claude-code
cat > ~/.config/claude-code/media-upload.json << EOF
{
"mc_path": "${MC_PATH}",
"public_url": "${PUBLIC_URL}",
"organize_by": "date",
"max_file_size_mb": 100
}
EOF
chmod 600 ~/.config/claude-code/media-upload.json
echo "✅ Configuration saved"
```
## Batch Upload
При загрузке нескольких файлов:
```bash
# Пример: загрузи все png из ./screenshots/
# Защита от пустого glob
shopt -s nullglob
files=(./screenshots/*.png)
shopt -u nullglob
if [[ ${#files[@]} -eq 0 ]]; then
echo "❌ Файлы не найдены: ./screenshots/*.png"
exit 1
fi
success=()
failed=()
for file in "${files[@]}"; do
if upload_file "$file"; then
success+=("$file")
else
failed+=("$file")
fi
done
```
### Частичный успех
При ошибке части файлов показать:
- Успешные с URL
- Неуспешные с причиной ошибки
- **Не откатывать** успешные загрузки
Формат вывода:
```
⚠️ Uploaded 3 of 5 files:
✅ Успешно:
- screenshot-1.png → https://cdn...
- screenshot-2.png → https://cdn...
- screenshot-3.png → https://cdn...
❌ Ошибки:
- screenshot-4.png: Connection timeout
- screenshot-5.png: File too large (120MB > 100MB limit)
```
## История загрузок
**Файл**: `~/.media-upload-history.json`
```json
{
"uploads": [
{
"file": "/tmp/page-2024-01-31-143052.png",
"url": "https://cdn.example.com/screenshots/2024/01/31/screenshot-2024-01-31-143052.png",
"size": 245678,
"timestamp": "2024-01-31T14:30:52Z"
}
]
}
```
**Просмотр истории**:
```bash
jq '.uploads[-10:]' ~/.media-upload-history.json
```
## Выход после успешной загрузки
### Одиночный файл:
**Публичный URL** (короткий, постоянный):
```
✅ Image uploaded!
URL: https://s3.example.com/bucket/2024/01/31/screenshot.png
Markdown: 
Size: 245 KB
```
**Presigned URL** (длинный, временный):
```
✅ Image uploaded!
URL: https://s3.example.com/bucket/2024/01/31/screenshot.png?X-Amz-...
⏰ Expires: 7 days
Markdown: 
Size: 245 KB
Tip: Настройте публичный доступ к bucket для коротких постоянных ссылок
```
### Batch:
```
✅ 5 images uploaded!
| File | URL | Size |
|------|-----|------|
| screenshot-1.png | https://cdn... | 120 KB |
| screenshot-2.png | https://cdn... | 245 KB |
| ... | ... | ... |
Total: 1.2 MB
Markdown (all):


```
## Edge Cases
| Ситуация | Действие |
|----------|----------|
| `mc` не установлен | Показать `brew install minio-mc` / `apt install minio-mc` |
| Alias не настроен | Показать `mc alias set screenshots ...` |
| Файл не найден | Спросить путь явно |
| Неподдерживаемый формат | Предупредить, но загрузить если попросят |
| Файл слишком большой | Показать размер, запросить подтверждение (>50MB) или отказать (>100MB) |
| Нет Playwright скриншотов | Спросить путь явно |
| Ошибка загрузки | Показать stderr от mc |
| Спецсимволы в имени | Санитизировать: `my file (1).png` → `my-file-1.png` |
| Пустой файл (0 байт) | Показать ошибку: "Файл пустой, загрузка отменена" |
| Bucket приватный (403) | В режиме `auto` — fallback на presigned URL |
| Presigned URL слишком длинный | Рекомендовать настроить публичный bucket |
| SSL ошибка при проверке | Использовать `curl -k` или сразу presigned |
| Region mismatch (Selectel) | Установить `MC_REGION=ru-3` перед командами mc |
| SSL certificate verify failed | Использовать `mc cp --insecure` или `aws --no-verify-ssl` |
## Рекомендации по настройке публичного доступа
Для коротких URL без presigned подписей:
### Selectel Cloud Storage
**⚠️ ВАЖНО: S3 API Selectel НЕ поддерживает анонимный доступ!**
Даже если бакет настроен как "Публичный", запросы через S3 API (`s3.ru-3.storage.selcloud.ru`) требуют подписи.
**Варианты решения:**
1. **Presigned URLs** (рекомендуется):
- Используйте `url_mode: "presigned"` в конфигурации
- Максимальный срок — 7 дней (ограничение mc/S3)
- URL длинный, но гарантированно работает
2. **Домен selstorage.ru** (публичный хостинг):
- В консоли включите "Веб-сайт" для бакета
- URL формата: `https://UUID.selstorage.ru/path/file.png`
- Требует дополнительной настройки и может иметь проблемы с SSL
3. **CDN Selectel** (лучший вариант для продакшена):
- Подключите CDN к бакету
- URL через `*.selcdn.ru` поддерживает анонимный доступ
- Быстрее и надёжнее
Подробнее: https://qna.habr.com/q/1147270
### MinIO
```bash
mc anonymous set download ALIAS/BUCKET
```
### AWS S3
```bash
aws s3api put-bucket-policy --bucket BUCKET --policy '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::BUCKET/*"
}]
}'
```Related Skills
zellij-tab-pane
**UNIVERSAL TRIGGER**: OPEN/CREATE/RUN tab or pane IN zellij. Modes: empty tab/pane, shell command in tab/pane, Claude session in tab/pane, GitHub issue in tab/pane. Examples: "open new tab", "run npm test in pane", "execute plan in tab", "start issue #123 in pane", "открой вкладку", "запусти тесты в панели", "делегируй в вкладку", "стартани issue в панели"
task-routing
**UNIVERSAL TRIGGER**: ROUTE/TAKE/IMPLEMENT any task FROM a URL or issue reference **URLs & References**: - "get task from github.com/.../issues/N", "fetch spec from docs.google.com/..." - "retrieve task from https://..." **Local File Paths**: - "реализуй /path/to/plan.md", "выполни ./docs/plans/fix.md" - "take /home/user/plan.md", "implement /abs/path/to/plan.md" **Action Triggers (EN)**: - "take this task", "implement this spec", "do issue #NNN" - "route task", "route this", "start issue #NNN" - "check this task", "analyze task" **Triggers (RU)**: - "возьми задачу", "сделай задачу", "реализуй по спеке" - "сделай issue #NNN", "возьми issue #NNN" **#NNN**: action-слово + "issue"/"задачу" обязательны. Голый #NNN -- НЕ триггер. **Should NOT activate** (handled by other skills): - "show/read/view issue #N" (github-issues) - "what does issue #N say" (github-issues) - "edit/close/mark done issue" (github-issues) - "review spec", "check spec", "analyze requirements" (spec-review) - bare GitHub issue URL without action verb (github-issues) TRIGGERS: route task, route this, возьми задачу, сделай задачу, take this task, implement this spec, implement this issue, get task from, check this task, analyze task, retrieve spec, fetch task, реализуй по спеке, сделай issue, do issue, start issue, github.com/issues, docs.google.com/document, /docs/plans, ./docs/plans, /tmp/plan, local file, локальный файл
spec-review
**UNIVERSAL TRIGGER**: Ревью спецификаций и ТЗ на гапы, нестыковки и противоречия. Используй когда: - "get/show/list/display spec issues", "retrieve spec analysis" - "check/analyze/fetch spec review", "review spec" - "проверь спецификацию/ТЗ", "ревью спеки", "проанализируй ТЗ" - "найди гапы в требованиях", "найди нестыковки/противоречия" - пользователь дал ссылку на Google Doc, GitHub issue или Docmost-документ со спецификацией - пользователь вставил текст спецификации и просит проверить **Уровни глубины**: - `--quick` / `-q` — только критические блокеры (быстро) - `--standard` / `-s` — критические + высокие (по умолчанию) - `--deep` / `-d` — все проблемы включая средние - `--exhaustive` / `-e` — полный аудит с рекомендациями - `--no-ask` — использовать standard без вопроса (для CI/CD) **Ключевые слова для уровней**: - "быстро проверь", "только блокеры" -> quick - "тщательно", "подробно", "глубоко" -> deep - "полный аудит", "исчерпывающий" -> exhaustive **Google Doc**: - "проверь спеку docs.google.com/document/d/XXX" - "ревью этого ТЗ [ссылка на Google Doc]" **Docmost**: - "проверь спеку https://docs.company.com/p/XXXXXXXX" - "ревью этого ТЗ в Docmost [ссылка]" **GitHub Issue** (ТОЛЬКО с ревью-контекстом!): - "проанализируй issue #123" (ревью-слово: "проанализируй") - "проверь спецификацию github.com/.../issues/456" (ревью-слово: "проверь") - голый "issue #123" без ревью-контекста -- НЕ триггер (github-issues или task-routing) **Текст в сообщении**: - "проверь это ТЗ: [текст спецификации]" - пользователь вставил большой текст и просит ревью **Локальный файл**: - "проверь спеку в docs/spec.md" - "сделай ревью файла requirements.txt" TRIGGERS: спецификация, ТЗ, spec, specification, requirements, проверь спеку, ревью спеки, review spec, analyze spec, найди гапы, найди противоречия, найди нестыковки, docs.google.com/document, github.com/issues, docmost, /p/, техническое задание, требования, acceptance criteria, проанализируй требования, check requirements, --quick, -q, --deep, -d, --exhaustive, -e, --no-ask, быстро проверь, тщательно проанализируй, полный аудит, только блокеры, глубокий анализ, исчерпывающий
pr-review-fix-loop
**UNIVERSAL TRIGGER**: Iterative PR review + autofix loop. Use when user wants to review, check, or fix PR changes automatically. Common patterns: - "review my PR", "check my PR", "review changes" - "fix review comments", "address review findings" - "run review loop", "autofix PR issues" - "проверь мой PR", "ревью PR", "проверь изменения" - "исправь замечания ревью", "пофикси замечания" - "запусти ревью", "автоисправление PR" **PR Review** (iterative review + fix cycle): - "review and fix my PR", "check PR and fix issues" - "iterate on PR review", "review loop" - "проверь и исправь PR", "итеративное ревью" **Code Review Fix** (address existing review comments): - "fix review comments", "address PR feedback" - "fix code review issues", "resolve review findings" - "исправь замечания", "пофикси комментарии ревью" **Codex Review** (standalone Codex CLI review): - "codex review", "run codex on my changes" - "codex ревью", "запусти codex" TRIGGERS: review PR, check PR, fix PR, review changes, review loop, autofix, pr review, code review fix, address review, fix comments, review findings, iterate review, codex review, run codex, проверь PR, ревью PR, исправь замечания, пофикси PR, проверь изменения, запусти ревью, автоисправление, codex ревью, замечания ревью, фикс PR
long-running-harness
**UNIVERSAL TRIGGER**: Use when user wants to START/CONTINUE/MANAGE a long-running development project across multiple sessions. Common patterns: - "start/init/begin new project [description]" - "continue/resume working on [project]" - "начать/инициализировать проект", "продолжить работу над проектом" - "set up harness for [project]", "create project scaffolding" Session types supported: **Initialize (first run)**: - "init long-running project", "start new multi-session project" - "set up project harness", "create progress tracking" - "initialize [web-app/api/cli] project", "начать долгий проект" **Continue (subsequent sessions)**: - "continue project", "resume work", "продолжить работу" - "pick up where I left off", "what's next", "следующая фича" - "next feature", "continue implementation" **Status & Progress**: - "show project progress", "what features are done" - "project status", "статус проекта", "что сделано" - "remaining features", "what's left to do" **Management**: - "mark feature as done", "update progress" - "add new feature to list", "reprioritize features" Context patterns: - "get/show/list project progress" - "check project status" - "what features in project" - "display remaining features" - "fetch session history" - "retrieve progress log" TRIGGERS: long-running, multi-session, project harness, initialize project, continue project, resume work, progress tracking, feature list, session handoff, incremental development, cross-session, долгий проект, продолжить работу, прогресс проекта, следующая сессия, инициализация проекта, get project status, show features, list remaining, check progress, display status, fetch history, retrieve log, what features done, start harness, begin project, resume session, next feature, pick up work, update progress, mark done, end session Based on Anthropic's research on effective harnesses for long-running agents. Source: https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents
himalaya
**UNIVERSAL TRIGGER**: Use when user wants to READ/SEND email. Common patterns: - "check my email/inbox", "show unread" - "send email to [recipient]" - "проверить почту", "отправить письмо" **Reading**: - "check inbox", "show unread emails", "what's in my mail" - "read email from [sender]", "find emails about [topic]" - "show email folders", "list mail folders" - "проверить входящие", "непрочитанные", "что в почте", "покажи папки" **Sending**: - "send email to [address]", "compose email" - "reply to email", "forward email" - "отправить письмо", "ответить на письмо", "написать письмо" **Accounts**: - "list email accounts", "switch to work email" - "список почтовых аккаунтов", "использовать рабочую почту" ❌ **Should NOT activate**: - "what is SMTP protocol" (general question) - "email regex validation" (programming) - "install himalaya" (setup) TRIGGERS: email, mail, inbox, send, check, read, show, list, get, compose, reply, forward, unread, fetch, view, display, folder, folders, отправить, проверить, прочитать, показать, получить, письмо, почта, папка, папки
worktree-init-script
**UNIVERSAL TRIGGER**: Use when creating git worktrees in projects with init.sh - extends using-git-worktrees to run project-specific initialization script after worktree setup. **Activation**: Automatic when `using-git-worktrees` is invoked and `init.sh` exists in project root. **Setup**: "run init.sh", "initialize worktree", "project setup script" **Create**: "create worktree", "set up workspace", "new worktree" **Check**: "check init.sh", "verify project setup" TRIGGERS: init.sh, worktree init, worktree setup, project setup script, run init, initialize worktree, worktree initialization, create worktree init, setup worktree project, инициализация worktree, запустить init.sh, скрипт инициализации, настройка worktree, создать worktree с init
plan-to-issue
**UNIVERSAL TRIGGER**: SAVE/PUBLISH/EXPORT implementation plan TO GitHub issue for separate session execution. Common patterns: - "save/publish/export plan to issue" - "create issue from plan", "plan to github" - "сохрани план в issue", "создай issue из плана" **Save Plan**: - "save plan to issue", "publish plan to github" - "сохрани план в issue", "экспортируй план" **Create Issue from Plan**: - "create issue from plan", "plan as issue" - "создай issue из плана", "план в задачу" **Execute Later**: - "save for separate session", "execute plan later" - "сохрани для отдельной сессии", "выполнить потом" **Should NOT activate**: - General "create issue" without plan context - Reading existing issues - Working with issue checkboxes TRIGGERS: plan to issue, save plan, export plan, publish plan, plan as issue, issue from plan, plan to github, сохрани план, план в issue, экспорт плана, план в задачу, save for later, execute later, separate session, сохрани для сессии, выполнить потом, план в github
github-issues
**UNIVERSAL TRIGGER**: Use when user mentions GitHub issue URL or asks to read/work with GitHub issues. **Default handler**: Bare GitHub issue URL without action verb -> github-issues (read mode). If user sends just a URL like "https://github.com/org/repo/issues/42" with no action word, this skill handles it. **CRITICAL RULE**: ALWAYS use `gh` CLI for GitHub issues, NEVER use WebFetch! **Reading**: "read issue #N", "show issue", "прочитай задачу" ✅ **Checkboxes**: "mark done", "complete step", "отметь пункт" **Sub-issues**: "create sub-issue", "link as child", "подзадача" **Management**: "edit issue", "close issue", "add label" ️ **Images**: "download images from issue", "скачать картинки" TRIGGERS: github.com/issues, issue #, read issue, show issue, view issue, прочитай issue, покажи issue, задача ✅ checkbox, mark done, complete step, check off, отметь пункт, закрой этап sub-issue, subtask, child issue, parent issue, подзадача, создай подзадачу edit issue, close issue, reopen issue, issue labels, create issue, update task ️ download images, issue attachments, скачать картинки
doc-validate
**UNIVERSAL TRIGGER**: Validate/check/lint documentation quality. **Formatting**: "validate docs", "doc lint", "проверь документацию" **Links**: "broken links", "orphan docs", "битые ссылки" **Terms**: "check glossary", "терминология", "synonyms" **Viewpoints**: "check artifacts", "state diagrams", "threat model" ⚡ **Contradictions**: "find conflicts", "противоречия" ️ **Gaps**: "missing coverage", "пробелы", "completeness" **Review**: "full audit", "полный аудит", "/doc:review" TRIGGERS: doc lint, validate docs, проверь документацию, broken links, orphan, glossary, viewpoints, contradictions, gaps, coverage, /doc:lint, /doc:links, /doc:terms, /doc:viewpoints, /doc:contradictions, /doc:gaps, /doc:review
bugsnag
**UNIVERSAL TRIGGER**: Use when user wants to GET/FETCH/RETRIEVE any data FROM Bugsnag. Common patterns: - "get/show/list/display [something] from bugsnag" - "получить/показать/вывести [что-то] из bugsnag" - "bugsnag [organizations/projects/errors/details/events/comments/stats]" - "what [data] in bugsnag", "check bugsnag [resource]" Specific data types supported: **Organizations & Projects**: - "list bugsnag organizations/orgs", "show organizations" - "list bugsnag projects", "available projects", "проекты bugsnag" **Errors (viewing)**: - "show/list bugsnag errors", "что в bugsnag", "check bugsnag" - "open errors", "error list", "ошибки bugsnag", "открытые ошибки" - "errors with severity error/warning", "filter bugsnag errors" **Error Details**: - "bugsnag details for <id>", "error details", "детали ошибки" - "show stack trace", "error context", "what happened in error" - "events for error", "error timeline", "события ошибки" **Comments**: - "show comments for error", "error comments", "комментарии ошибки" - "bugsnag discussion", "what comments on error" **Analysis**: - "analyze bugsnag errors", "error patterns", "анализ ошибок" - "bugsnag statistics", "error trends", "что происходит в bugsnag" ✅ **Management** (write operations): - "mark as fixed/resolved", "fix error", "resolve error", "close error" - "закрыть ошибку", "отметить как решенную", "исправить ошибку" - "add comment to error", "comment on bugsnag error" - NOTE: Fix/Resolve/Close are synonyms - all mark error as resolved in Bugsnag TRIGGERS: bugsnag, получить из bugsnag, показать bugsnag, список bugsnag, bugsnag data, bugsnag info, check bugsnag, what in bugsnag, bugsnag status, error tracking, error monitoring, production errors, stack trace, bugsnag organizations, bugsnag projects, bugsnag errors, bugsnag details, bugsnag events, bugsnag comments, bugsnag analysis, ошибки в bugsnag, что в bugsnag, проверить bugsnag, данные bugsnag, fix error, resolve error, close error, закрыть ошибку, исправить ошибку, отметить как решенную This skill provides complete Bugsnag API integration for viewing and managing error tracking data via Ruby helper scripts.
You are a professional Chief Marketing Officer. Your task is to help a user start and grow their social media presence organically through a series of questions and generate a growthplan.md blueprint.
Follow these instructions: