chore(skills): удалены неиспользуемые скиллы, review-homework вынесен
- Зачем: - разгрузить контекст сессии — каждый скилл грузит описание в каждый проект; убираем то, чем не пользуемся. - Что: - удалены security-audit, proxy-debug, dotfiles-check, jupyter-notebook, docstring. - review-homework удалён отсюда и перенесён в репозиторий kb-mentoring (.skills/), где он тематически на месте. - Проверка: - git status agents/.agents/skills — перечисленных папок больше нет; восстановимы из git-истории при необходимости.
This commit is contained in:
1 parent
01d1de88d3
commit
ce5fb6bea7
18 files changed
-1749
No files matched your search
@@ -1,445 +0,0 @@
|
||||
---
|
||||
name: python-docstring
|
||||
description: A skill for writing consistent, well-structured Python docstrings following the Google style convention.
|
||||
metadata:
|
||||
author: Deerhide
|
||||
version: 1.0.0
|
||||
---
|
||||
|
||||
# Python Docstring Skill
|
||||
|
||||
## When to use this skill?
|
||||
|
||||
- Use this skill when writing or updating Python documentation strings (docstrings).
|
||||
- This skill is useful for ensuring consistent documentation across a Python codebase.
|
||||
- It should be applied when documenting modules, classes, functions, methods, and attributes.
|
||||
- Use it during code reviews to verify docstring quality and completeness.
|
||||
|
||||
# Language
|
||||
|
||||
Язык docstring'ов определяется по проекту: если в существующем коде комментарии и docstring'ы на русском — пиши на русском, если на английском — на английском. Не смешивай языки внутри одного проекта.
|
||||
|
||||
# Docstring Style Convention
|
||||
|
||||
We follow the **Google style** docstring convention. This style is chosen for its:
|
||||
- Readability and clean formatting
|
||||
- Wide adoption in the Python community
|
||||
- Excellent support in documentation tools (Sphinx, MkDocs)
|
||||
- Native support in linting tools (Ruff, Pylint)
|
||||
|
||||
# Module Docstrings
|
||||
|
||||
Every Python module should start with a docstring describing its purpose.
|
||||
|
||||
```python
|
||||
"""Module for handling user authentication and session management.
|
||||
|
||||
This module provides utilities for user authentication, token generation,
|
||||
and session lifecycle management. It integrates with OAuth2 providers
|
||||
and supports JWT-based authentication.
|
||||
|
||||
Example:
|
||||
Basic usage of the authentication service::
|
||||
|
||||
from auth import AuthService
|
||||
|
||||
service = AuthService(secret_key="my-secret")
|
||||
token = service.create_token(user_id=123)
|
||||
|
||||
Attributes:
|
||||
DEFAULT_TOKEN_EXPIRY (int): Default token expiration time in seconds.
|
||||
SUPPORTED_ALGORITHMS (list): List of supported JWT algorithms.
|
||||
|
||||
Todo:
|
||||
* Add support for refresh tokens
|
||||
* Implement rate limiting for failed attempts
|
||||
"""
|
||||
|
||||
DEFAULT_TOKEN_EXPIRY = 3600
|
||||
SUPPORTED_ALGORITHMS = ["HS256", "RS256"]
|
||||
```
|
||||
|
||||
# Class Docstrings
|
||||
|
||||
Class docstrings should describe the class purpose and list its attributes.
|
||||
|
||||
```python
|
||||
class UserRepository:
|
||||
"""Repository for managing user data persistence.
|
||||
|
||||
This class provides CRUD operations for user entities and handles
|
||||
database connections and transactions.
|
||||
|
||||
Attributes:
|
||||
connection: Database connection instance.
|
||||
table_name: Name of the users table.
|
||||
cache_enabled: Whether caching is enabled for queries.
|
||||
|
||||
Example:
|
||||
Creating and using a repository::
|
||||
|
||||
repo = UserRepository(connection=db_conn)
|
||||
user = repo.find_by_id(user_id=42)
|
||||
repo.save(user)
|
||||
"""
|
||||
|
||||
def __init__(self, connection: DatabaseConnection) -> None:
|
||||
"""Initialize the UserRepository.
|
||||
|
||||
Args:
|
||||
connection: Active database connection to use for operations.
|
||||
"""
|
||||
self.connection = connection
|
||||
self.table_name = "users"
|
||||
self.cache_enabled = True
|
||||
```
|
||||
|
||||
# Function and Method Docstrings
|
||||
|
||||
Functions and methods should document their purpose, arguments, return values, and exceptions.
|
||||
|
||||
## Basic Function
|
||||
|
||||
```python
|
||||
def calculate_discount(price: float, percentage: float) -> float:
|
||||
"""Calculate the discounted price.
|
||||
|
||||
Args:
|
||||
price: Original price of the item.
|
||||
percentage: Discount percentage (0-100).
|
||||
|
||||
Returns:
|
||||
The discounted price after applying the percentage reduction.
|
||||
|
||||
Raises:
|
||||
ValueError: If percentage is not between 0 and 100.
|
||||
TypeError: If price or percentage are not numeric.
|
||||
|
||||
Example:
|
||||
>>> calculate_discount(100.0, 20)
|
||||
80.0
|
||||
"""
|
||||
if not 0 <= percentage <= 100:
|
||||
raise ValueError("Percentage must be between 0 and 100")
|
||||
return price * (1 - percentage / 100)
|
||||
```
|
||||
|
||||
## Method with Complex Arguments
|
||||
|
||||
```python
|
||||
def create_user(
|
||||
self,
|
||||
username: str,
|
||||
email: str,
|
||||
*,
|
||||
role: str = "user",
|
||||
metadata: dict[str, Any] | None = None,
|
||||
) -> User:
|
||||
"""Create a new user in the system.
|
||||
|
||||
Creates a user entity with the provided information and persists
|
||||
it to the database. Sends a welcome email upon successful creation.
|
||||
|
||||
Args:
|
||||
username: Unique username for the new user. Must be alphanumeric
|
||||
and between 3-50 characters.
|
||||
email: Valid email address for the user.
|
||||
role: User role assignment. Defaults to "user".
|
||||
Valid options are "user", "admin", "moderator".
|
||||
metadata: Optional dictionary of additional user metadata.
|
||||
Keys must be strings, values can be any JSON-serializable type.
|
||||
|
||||
Returns:
|
||||
The newly created User instance with assigned ID.
|
||||
|
||||
Raises:
|
||||
DuplicateUserError: If username or email already exists.
|
||||
ValidationError: If input validation fails.
|
||||
DatabaseError: If database operation fails.
|
||||
|
||||
Note:
|
||||
This method triggers a background task for sending the welcome email.
|
||||
The email sending is non-blocking and failures are logged but not raised.
|
||||
|
||||
Example:
|
||||
Creating a basic user::
|
||||
|
||||
user = service.create_user(
|
||||
username="johndoe",
|
||||
email="john@example.com"
|
||||
)
|
||||
|
||||
Creating an admin user with metadata::
|
||||
|
||||
admin = service.create_user(
|
||||
username="admin",
|
||||
email="admin@example.com",
|
||||
role="admin",
|
||||
metadata={"department": "IT"}
|
||||
)
|
||||
"""
|
||||
```
|
||||
|
||||
## Async Functions
|
||||
|
||||
```python
|
||||
async def fetch_user_data(user_id: int, timeout: float = 30.0) -> UserData:
|
||||
"""Fetch user data from the remote service.
|
||||
|
||||
Asynchronously retrieves user information from the external API
|
||||
with automatic retry logic for transient failures.
|
||||
|
||||
Args:
|
||||
user_id: Unique identifier of the user to fetch.
|
||||
timeout: Maximum time in seconds to wait for response.
|
||||
Defaults to 30.0 seconds.
|
||||
|
||||
Returns:
|
||||
UserData object containing the user's information.
|
||||
|
||||
Raises:
|
||||
UserNotFoundError: If no user exists with the given ID.
|
||||
TimeoutError: If the request exceeds the timeout duration.
|
||||
ServiceUnavailableError: If the remote service is unreachable.
|
||||
"""
|
||||
```
|
||||
|
||||
# Generator and Iterator Docstrings
|
||||
|
||||
```python
|
||||
def paginate_results(
|
||||
query: Query,
|
||||
page_size: int = 100,
|
||||
) -> Iterator[list[Record]]:
|
||||
"""Paginate through query results.
|
||||
|
||||
Yields pages of records from the query, handling cursor-based
|
||||
pagination automatically.
|
||||
|
||||
Args:
|
||||
query: Database query to paginate.
|
||||
page_size: Number of records per page. Defaults to 100.
|
||||
|
||||
Yields:
|
||||
Lists of Record objects, each list containing up to page_size items.
|
||||
|
||||
Example:
|
||||
>>> for page in paginate_results(query, page_size=50):
|
||||
... process_records(page)
|
||||
"""
|
||||
```
|
||||
|
||||
# Property Docstrings
|
||||
|
||||
```python
|
||||
@property
|
||||
def full_name(self) -> str:
|
||||
"""Return the full name of the user.
|
||||
|
||||
Combines first_name and last_name with proper spacing.
|
||||
Returns an empty string if both names are unset.
|
||||
"""
|
||||
return f"{self.first_name} {self.last_name}".strip()
|
||||
|
||||
|
||||
@property
|
||||
def is_active(self) -> bool:
|
||||
"""Return whether the user account is currently active.
|
||||
|
||||
An account is considered active if it has been verified
|
||||
and has not been suspended or deleted.
|
||||
"""
|
||||
return self.verified and not self.suspended
|
||||
```
|
||||
|
||||
# Context Manager Docstrings
|
||||
|
||||
```python
|
||||
@contextmanager
|
||||
def database_transaction(
|
||||
connection: Connection,
|
||||
isolation_level: str = "READ_COMMITTED",
|
||||
) -> Iterator[Transaction]:
|
||||
"""Context manager for database transactions.
|
||||
|
||||
Provides automatic commit on success and rollback on failure.
|
||||
Nested transactions are supported via savepoints.
|
||||
|
||||
Args:
|
||||
connection: Active database connection.
|
||||
isolation_level: Transaction isolation level.
|
||||
Options: "READ_UNCOMMITTED", "READ_COMMITTED",
|
||||
"REPEATABLE_READ", "SERIALIZABLE".
|
||||
Defaults to "READ_COMMITTED".
|
||||
|
||||
Yields:
|
||||
Transaction object for executing queries.
|
||||
|
||||
Raises:
|
||||
TransactionError: If transaction cannot be started.
|
||||
|
||||
Example:
|
||||
>>> with database_transaction(conn) as tx:
|
||||
... tx.execute("INSERT INTO users VALUES (?)", [user])
|
||||
"""
|
||||
```
|
||||
|
||||
# Dataclass and Pydantic Model Docstrings
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class OrderItem:
|
||||
"""Represents a single item in an order.
|
||||
|
||||
Attributes:
|
||||
product_id: Unique identifier of the product.
|
||||
quantity: Number of units ordered. Must be positive.
|
||||
unit_price: Price per unit in the order currency.
|
||||
discount: Applied discount as a decimal (0.0-1.0).
|
||||
"""
|
||||
|
||||
product_id: str
|
||||
quantity: int
|
||||
unit_price: Decimal
|
||||
discount: Decimal = Decimal("0.0")
|
||||
|
||||
|
||||
class UserSettings(BaseModel):
|
||||
"""User preference settings.
|
||||
|
||||
Stores user-configurable settings for the application,
|
||||
including notification preferences and display options.
|
||||
|
||||
Attributes:
|
||||
theme: UI theme preference. Either "light" or "dark".
|
||||
notifications_enabled: Whether to send notifications.
|
||||
language: Preferred language code (ISO 639-1).
|
||||
timezone: User's timezone (IANA format).
|
||||
"""
|
||||
|
||||
theme: Literal["light", "dark"] = "light"
|
||||
notifications_enabled: bool = True
|
||||
language: str = "en"
|
||||
timezone: str = "UTC"
|
||||
```
|
||||
|
||||
# Enum Docstrings
|
||||
|
||||
```python
|
||||
class OrderStatus(Enum):
|
||||
"""Status values for order lifecycle.
|
||||
|
||||
Attributes:
|
||||
PENDING: Order created but not yet processed.
|
||||
CONFIRMED: Order confirmed and awaiting fulfillment.
|
||||
SHIPPED: Order has been shipped to customer.
|
||||
DELIVERED: Order successfully delivered.
|
||||
CANCELLED: Order was cancelled before fulfillment.
|
||||
"""
|
||||
|
||||
PENDING = "pending"
|
||||
CONFIRMED = "confirmed"
|
||||
SHIPPED = "shipped"
|
||||
DELIVERED = "delivered"
|
||||
CANCELLED = "cancelled"
|
||||
```
|
||||
|
||||
# Exception Docstrings
|
||||
|
||||
```python
|
||||
class ValidationError(Exception):
|
||||
"""Raised when input validation fails.
|
||||
|
||||
This exception is raised when user input or API request data
|
||||
fails validation rules.
|
||||
|
||||
Attributes:
|
||||
field: Name of the field that failed validation.
|
||||
message: Human-readable error message.
|
||||
code: Machine-readable error code for client handling.
|
||||
|
||||
Example:
|
||||
>>> raise ValidationError(
|
||||
... field="email",
|
||||
... message="Invalid email format",
|
||||
... code="INVALID_EMAIL"
|
||||
... )
|
||||
"""
|
||||
|
||||
def __init__(self, field: str, message: str, code: str) -> None:
|
||||
"""Initialize ValidationError.
|
||||
|
||||
Args:
|
||||
field: Name of the field that failed validation.
|
||||
message: Human-readable description of the error.
|
||||
code: Machine-readable error code.
|
||||
"""
|
||||
self.field = field
|
||||
self.message = message
|
||||
self.code = code
|
||||
super().__init__(f"{field}: {message}")
|
||||
```
|
||||
|
||||
# Docstring Sections Reference
|
||||
|
||||
The following sections are supported in Google style docstrings:
|
||||
|
||||
| Section | Purpose |
|
||||
|---------|---------|
|
||||
| `Args:` | Document function/method parameters |
|
||||
| `Returns:` | Describe the return value |
|
||||
| `Yields:` | Describe yielded values (generators) |
|
||||
| `Raises:` | List exceptions that may be raised |
|
||||
| `Attributes:` | Document class/module attributes |
|
||||
| `Example:` / `Examples:` | Provide usage examples |
|
||||
| `Note:` | Additional information or caveats |
|
||||
| `Warning:` | Important warnings for users |
|
||||
| `Todo:` | Future improvements or tasks |
|
||||
| `See Also:` | References to related functions/classes |
|
||||
|
||||
# Best Practices
|
||||
|
||||
1. **Be Concise**: First line should be a brief summary under 79 characters.
|
||||
2. **Use Imperative Mood**: Write "Calculate the sum" not "Calculates the sum".
|
||||
3. **Document All Public APIs**: Every public function, class, and method needs a docstring.
|
||||
4. **Rely on Type Hints**: Avoid duplicating type information in docstrings when type hints are present. Modern documentation tools extract types from annotations.
|
||||
5. **Provide Examples**: Complex functions benefit from usage examples.
|
||||
6. **Document Exceptions**: List all exceptions that can be raised.
|
||||
7. **Keep Updated**: Update docstrings when code changes.
|
||||
8. **Use Proper Indentation**: Continuation lines should be indented consistently.
|
||||
|
||||
# Linting Configuration
|
||||
|
||||
Recommended Ruff configuration for `pyproject.toml`:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
line-length = 120
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["D", "F", "E", "W", "I", "UP", "B", "SIM", "S", "A", "C90", "RET", "PERF"]
|
||||
|
||||
[tool.ruff.lint.pydocstyle]
|
||||
convention = "google"
|
||||
```
|
||||
|
||||
Key rule groups: **D** (docstrings), **F** (pyflakes), **E/W** (pycodestyle),
|
||||
**I** (imports), **UP** (pyupgrade), **B** (bugbear), **SIM** (simplify),
|
||||
**S** (security/bandit), **A** (builtins shadowing), **C90** (complexity),
|
||||
**RET** (return statements), **PERF** (performance).
|
||||
|
||||
# Common Ruff Docstring Rules
|
||||
|
||||
| Rule | Description |
|
||||
|------|-------------|
|
||||
| D100 | Missing docstring in public module |
|
||||
| D101 | Missing docstring in public class |
|
||||
| D102 | Missing docstring in public method |
|
||||
| D103 | Missing docstring in public function |
|
||||
| D107 | Missing docstring in `__init__` |
|
||||
| D200 | One-line docstring should fit on one line |
|
||||
| D205 | 1 blank line required between summary and description |
|
||||
| D400 | First line should end with a period |
|
||||
| D401 | First line should be in imperative mood |
|
||||
| D417 | Missing argument descriptions in docstring |
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
name: dotfiles-check
|
||||
description: "Проверка целостности dotfiles: симлинки stow, права доступа, settings.local.json, bashrc. Вызывай когда пользователь просит проверить установку dotfiles или валидировать окружение."
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
# Инструкция
|
||||
|
||||
Запусти скрипт проверки:
|
||||
|
||||
```bash
|
||||
bash ~/.agents/skills/dotfiles-check/check.sh
|
||||
```
|
||||
|
||||
Если пользователь передал путь к dotfiles-репозиторию:
|
||||
|
||||
```bash
|
||||
bash ~/.agents/skills/dotfiles-check/check.sh $ARGUMENTS
|
||||
```
|
||||
|
||||
Скрипт сам обнаружит stow-пакеты, проверит симлинки, права и дополнительные условия из `install.sh`.
|
||||
|
||||
Если есть ошибки (exit code 1) — кратко прокомментируй что сломалось и предложи команды для починки.
|
||||
@@ -1,168 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Проверка целостности dotfiles-установки через stow.
|
||||
# Использование: bash check.sh [путь-к-dotfiles]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DOTFILES_DIR="${1:-$(cd "$(dirname "$0")/../../../.." && pwd)}"
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
ok=0; warn=0; fail=0
|
||||
|
||||
pass() { echo -e " ${GREEN}✅${NC} $*"; ok=$((ok + 1)); }
|
||||
skip() { echo -e " ${YELLOW}⚠️${NC} $*"; warn=$((warn + 1)); }
|
||||
err() { echo -e " ${RED}❌${NC} $*"; fail=$((fail + 1)); }
|
||||
|
||||
echo "Проверка dotfiles ($DOTFILES_DIR)"
|
||||
echo "═══════════════════════════════════════"
|
||||
|
||||
# --- 1. Stow-пакеты: проверка симлинков ---
|
||||
# Stow использует "tree folding": если вся директория принадлежит одному пакету,
|
||||
# создаётся один симлинк на директорию, а не на каждый файл внутри.
|
||||
# Поэтому проверяем точки входа верхнего уровня каждого пакета.
|
||||
|
||||
for pkg_dir in "$DOTFILES_DIR"/*/; do
|
||||
pkg=$(basename "$pkg_dir")
|
||||
[[ "$pkg" == .* ]] && continue
|
||||
# claude управляется вручную (симлинк settings.local.json), не через stow
|
||||
[[ "$pkg" == "claude" ]] && continue
|
||||
|
||||
# Точки входа — элементы первого уровня внутри пакета
|
||||
entries=()
|
||||
for entry in "$pkg_dir".* "$pkg_dir"*; do
|
||||
[ -e "$entry" ] || continue
|
||||
base=$(basename "$entry")
|
||||
[[ "$base" == "." || "$base" == ".." ]] && continue
|
||||
# Берём только dot-файлы/директории (то, что stow раскладывает в ~)
|
||||
[[ "$base" == .* ]] && entries+=("$base")
|
||||
done
|
||||
|
||||
[ ${#entries[@]} -eq 0 ] && continue
|
||||
|
||||
echo ""
|
||||
echo "$pkg (${#entries[@]} точек входа):"
|
||||
|
||||
for entry in "${entries[@]}"; do
|
||||
home_path="$HOME/$entry"
|
||||
expected="$DOTFILES_DIR/$pkg/$entry"
|
||||
|
||||
# Если это директория в пакете — stow мог создать симлинк на неё целиком
|
||||
# или "раскрыть" её и создать симлинки внутри. Проверяем оба варианта.
|
||||
if [ -L "$home_path" ]; then
|
||||
# Симлинк на верхнем уровне (tree folding)
|
||||
actual=$(readlink -f "$home_path" 2>/dev/null || true)
|
||||
expected_resolved=$(readlink -f "$expected" 2>/dev/null || true)
|
||||
if [ "$actual" = "$expected_resolved" ]; then
|
||||
pass "~/$entry"
|
||||
else
|
||||
err "~/$entry → $(readlink "$home_path") (ожидался $pkg/$entry)"
|
||||
fi
|
||||
elif [ -d "$home_path" ] && [ -d "$expected" ]; then
|
||||
# Директория раскрыта — проверяем файлы внутри (один уровень)
|
||||
inner_ok=0; inner_fail=0
|
||||
while IFS= read -r -d '' f; do
|
||||
fname=$(basename "$f")
|
||||
inner_home="$home_path/$fname"
|
||||
if [ -L "$inner_home" ]; then
|
||||
inner_actual=$(readlink -f "$inner_home" 2>/dev/null || true)
|
||||
inner_expected=$(readlink -f "$f" 2>/dev/null || true)
|
||||
if [ "$inner_actual" = "$inner_expected" ]; then
|
||||
inner_ok=$((inner_ok + 1))
|
||||
else
|
||||
inner_fail=$((inner_fail + 1))
|
||||
fi
|
||||
elif [ -e "$inner_home" ]; then
|
||||
inner_ok=$((inner_ok + 1)) # файл есть, но не симлинк — ок для stow unfolded
|
||||
else
|
||||
inner_fail=$((inner_fail + 1))
|
||||
fi
|
||||
done < <(find "$expected" -maxdepth 1 -not -path "$expected" -print0)
|
||||
|
||||
if [ "$inner_fail" -eq 0 ]; then
|
||||
pass "~/$entry/ ($inner_ok элементов)"
|
||||
else
|
||||
err "~/$entry/ — $inner_fail из $((inner_ok + inner_fail)) элементов отсутствуют"
|
||||
fi
|
||||
elif [ -e "$home_path" ]; then
|
||||
skip "~/$entry — обычный файл (не симлинк)"
|
||||
else
|
||||
err "~/$entry — не найден"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# --- 2. Дополнительные проверки из install.sh ---
|
||||
install_script="$DOTFILES_DIR/install.sh"
|
||||
if [ -f "$install_script" ]; then
|
||||
echo ""
|
||||
echo "Доп. проверки (install.sh):"
|
||||
|
||||
# Claude Code: ~/.claude должна быть директорией, не симлинком
|
||||
if [ -L "$HOME/.claude" ]; then
|
||||
err "~/.claude — симлинк (должна быть директория). Запустите install.sh"
|
||||
elif [ -d "$HOME/.claude" ]; then
|
||||
pass "~/.claude — директория (не симлинк)"
|
||||
else
|
||||
err "~/.claude — не найден"
|
||||
fi
|
||||
|
||||
# Claude Code: settings.local.json должен быть симлинком на репозиторий
|
||||
if [ -L "$HOME/.claude/settings.local.json" ]; then
|
||||
local_target=$(readlink -f "$HOME/.claude/settings.local.json" 2>/dev/null || true)
|
||||
local_expected=$(readlink -f "$DOTFILES_DIR/claude/.claude/settings.local.json" 2>/dev/null || true)
|
||||
if [ "$local_target" = "$local_expected" ]; then
|
||||
pass "~/.claude/settings.local.json → репозиторий"
|
||||
else
|
||||
err "~/.claude/settings.local.json → $local_target (ожидался $local_expected)"
|
||||
fi
|
||||
elif [ -f "$HOME/.claude/settings.local.json" ]; then
|
||||
err "~/.claude/settings.local.json — обычный файл (должен быть симлинк). Запустите install.sh"
|
||||
elif [ -e "$HOME/.claude/settings.local.json" ]; then
|
||||
err "~/.claude/settings.local.json — не файл и не симлинк. Удалите вручную и запустите install.sh"
|
||||
else
|
||||
err "~/.claude/settings.local.json — не найден (запустите install.sh)"
|
||||
fi
|
||||
|
||||
# skills симлинк
|
||||
if [ -L "$HOME/.claude/skills" ]; then
|
||||
pass "~/.claude/skills — симлинк"
|
||||
else
|
||||
skip "~/.claude/skills — не найден"
|
||||
fi
|
||||
|
||||
# bashrc
|
||||
if grep -q 'bash_custom' "$HOME/.bashrc" 2>/dev/null; then
|
||||
pass "~/.bashrc содержит подключение bash_custom"
|
||||
else
|
||||
skip "~/.bashrc не содержит bash_custom"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 3. Битые симлинки ---
|
||||
broken=$(find "$HOME" -maxdepth 3 -xtype l 2>/dev/null | grep -v '.cache\|.local/share\|node_modules\|.npm' | head -10)
|
||||
if [ -n "$broken" ]; then
|
||||
echo ""
|
||||
echo "Битые симлинки в ~:"
|
||||
while IFS= read -r link; do
|
||||
err "$link → $(readlink "$link") (цель не существует)"
|
||||
done <<< "$broken"
|
||||
fi
|
||||
|
||||
# --- 4. Секреты ---
|
||||
if [ -f "$HOME/.env.secrets" ]; then
|
||||
echo ""
|
||||
echo "Секреты:"
|
||||
pass "~/.env.secrets существует"
|
||||
fi
|
||||
|
||||
# --- Итого ---
|
||||
total=$((ok + warn + fail))
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════"
|
||||
echo -e "Итого: ${GREEN}$ok${NC}/${total} ✅, ${YELLOW}$warn${NC} ⚠️, ${RED}$fail${NC} ❌"
|
||||
|
||||
[ "$fail" -eq 0 ] && exit 0 || exit 1
|
||||
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf of
|
||||
any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don\'t include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,107 +0,0 @@
|
||||
---
|
||||
name: "jupyter-notebook"
|
||||
description: "Use when the user asks to create, scaffold, or edit Jupyter notebooks (`.ipynb`) for experiments, explorations, or tutorials; prefer the bundled templates and run the helper script `new_notebook.py` to generate a clean starting notebook."
|
||||
---
|
||||
|
||||
|
||||
# Jupyter Notebook Skill
|
||||
|
||||
Create clean, reproducible Jupyter notebooks for two primary modes:
|
||||
|
||||
- Experiments and exploratory analysis
|
||||
- Tutorials and teaching-oriented walkthroughs
|
||||
|
||||
Prefer the bundled templates and the helper script for consistent structure and fewer JSON mistakes.
|
||||
|
||||
## When to use
|
||||
- Create a new `.ipynb` notebook from scratch.
|
||||
- Convert rough notes or scripts into a structured notebook.
|
||||
- Refactor an existing notebook to be more reproducible and skimmable.
|
||||
- Build experiments or tutorials that will be read or re-run by other people.
|
||||
|
||||
## Decision tree
|
||||
- If the request is exploratory, analytical, or hypothesis-driven, choose `experiment`.
|
||||
- If the request is instructional, step-by-step, or audience-specific, choose `tutorial`.
|
||||
- If editing an existing notebook, treat it as a refactor: preserve intent and improve structure.
|
||||
|
||||
## Skill path (set once)
|
||||
|
||||
```bash
|
||||
export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
||||
export JUPYTER_NOTEBOOK_CLI="$CODEX_HOME/skills/jupyter-notebook/scripts/new_notebook.py"
|
||||
```
|
||||
|
||||
User-scoped skills install under `$CODEX_HOME/skills` (default: `~/.codex/skills`).
|
||||
|
||||
## Workflow
|
||||
1. Lock the intent.
|
||||
Identify the notebook kind: `experiment` or `tutorial`.
|
||||
Capture the objective, audience, and what "done" looks like.
|
||||
|
||||
2. Scaffold from the template.
|
||||
Use the helper script to avoid hand-authoring raw notebook JSON.
|
||||
|
||||
```bash
|
||||
uv run --python 3.12 python "$JUPYTER_NOTEBOOK_CLI" \
|
||||
--kind experiment \
|
||||
--title "Compare prompt variants" \
|
||||
--out output/jupyter-notebook/compare-prompt-variants.ipynb
|
||||
```
|
||||
|
||||
```bash
|
||||
uv run --python 3.12 python "$JUPYTER_NOTEBOOK_CLI" \
|
||||
--kind tutorial \
|
||||
--title "Intro to embeddings" \
|
||||
--out output/jupyter-notebook/intro-to-embeddings.ipynb
|
||||
```
|
||||
|
||||
3. Fill the notebook with small, runnable steps.
|
||||
Keep each code cell focused on one step.
|
||||
Add short markdown cells that explain the purpose and expected result.
|
||||
Avoid large, noisy outputs when a short summary works.
|
||||
|
||||
4. Apply the right pattern.
|
||||
For experiments, follow `references/experiment-patterns.md`.
|
||||
For tutorials, follow `references/tutorial-patterns.md`.
|
||||
|
||||
5. Edit safely when working with existing notebooks.
|
||||
Preserve the notebook structure; avoid reordering cells unless it improves the top-to-bottom story.
|
||||
Prefer targeted edits over full rewrites.
|
||||
If you must edit raw JSON, review `references/notebook-structure.md` first.
|
||||
|
||||
6. Validate the result.
|
||||
Run the notebook top-to-bottom when the environment allows.
|
||||
If execution is not possible, say so explicitly and call out how to validate locally.
|
||||
Use the final pass checklist in `references/quality-checklist.md`.
|
||||
|
||||
## Templates and helper script
|
||||
- Templates live in `assets/experiment-template.ipynb` and `assets/tutorial-template.ipynb`.
|
||||
- The helper script loads a template, updates the title cell, and writes a notebook.
|
||||
|
||||
Script path:
|
||||
- `$JUPYTER_NOTEBOOK_CLI` (installed default: `$CODEX_HOME/skills/jupyter-notebook/scripts/new_notebook.py`)
|
||||
|
||||
## Temp and output conventions
|
||||
- Use `tmp/jupyter-notebook/` for intermediate files; delete when done.
|
||||
- Write final artifacts under `output/jupyter-notebook/` when working in this repo.
|
||||
- Use stable, descriptive filenames (for example, `ablation-temperature.ipynb`).
|
||||
|
||||
## Dependencies (install only when needed)
|
||||
Prefer `uv` for dependency management.
|
||||
|
||||
Optional Python packages for local notebook execution:
|
||||
|
||||
```bash
|
||||
uv pip install jupyterlab ipykernel
|
||||
```
|
||||
|
||||
The bundled scaffold script uses only the Python standard library and does not require extra dependencies.
|
||||
|
||||
## Environment
|
||||
No required environment variables.
|
||||
|
||||
## Reference map
|
||||
- `references/experiment-patterns.md`: experiment structure and heuristics.
|
||||
- `references/tutorial-patterns.md`: tutorial structure and teaching flow.
|
||||
- `references/notebook-structure.md`: notebook JSON shape and safe editing rules.
|
||||
- `references/quality-checklist.md`: final validation checklist.
|
||||
@@ -1,6 +0,0 @@
|
||||
interface:
|
||||
display_name: "Jupyter Notebooks"
|
||||
short_description: "Create Jupyter notebooks for experiments and tutorials"
|
||||
icon_small: "./assets/jupyter-small.svg"
|
||||
icon_large: "./assets/jupyter.png"
|
||||
default_prompt: "Create a Jupyter notebook for this task with clear sections, runnable cells, and concise takeaways."
|
||||
@@ -1,110 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Experiment: TITLE\n",
|
||||
"\n",
|
||||
"Objective:\n",
|
||||
"- State the question you want to answer.\n",
|
||||
"- Define the success criteria.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Setup: imports and reproducibility\n",
|
||||
"from __future__ import annotations\n",
|
||||
"\n",
|
||||
"import random\n",
|
||||
"import statistics\n",
|
||||
"\n",
|
||||
"SEED = 7\n",
|
||||
"random.seed(SEED)\n",
|
||||
"SEED\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Plan\n",
|
||||
"\n",
|
||||
"- Hypothesis:\n",
|
||||
"- Variables to sweep:\n",
|
||||
"- Metrics to record:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Define parameters and lightweight helpers\n",
|
||||
"sample_size = 20\n",
|
||||
"values = [random.random() for _ in range(sample_size)]\n",
|
||||
"summary = {\n",
|
||||
" \"count\": len(values),\n",
|
||||
" \"mean\": statistics.fmean(values),\n",
|
||||
" \"min\": min(values),\n",
|
||||
" \"max\": max(values),\n",
|
||||
"}\n",
|
||||
"summary\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Results\n",
|
||||
"\n",
|
||||
"- Key observations:\n",
|
||||
"- Surprises or failure modes:\n",
|
||||
"- Decision: continue, pivot, or stop:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Record findings in a minimal, copy-pasteable structure\n",
|
||||
"result = {\n",
|
||||
" \"seed\": SEED,\n",
|
||||
" \"mean\": summary[\"mean\"],\n",
|
||||
" \"range\": summary[\"max\"] - summary[\"min\"],\n",
|
||||
"}\n",
|
||||
"result\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Next steps\n",
|
||||
"\n",
|
||||
"- What to try next:\n",
|
||||
"- What to document elsewhere (PRD, notes, issue):\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="21" fill="currentColor" viewBox="0 0 20 21">
|
||||
<path fill="currentColor" d="M4.582 17.078a1.48 1.48 0 0 1 1.066.395c.29.27.463.642.48 1.038v.11a1.509 1.509 0 0 1-.858 1.315 1.476 1.476 0 0 1-1.634-.256 1.504 1.504 0 0 1-.39-1.62 1.51 1.51 0 0 1 .52-.695 1.48 1.48 0 0 1 .816-.287Zm13.167-4.733a7.802 7.802 0 0 1-2.829 3.789 7.698 7.698 0 0 1-4.48 1.44 7.7 7.7 0 0 1-4.48-1.44 7.803 7.803 0 0 1-2.829-3.79c1.424 1.704 4.168 2.854 7.308 2.854 3.14 0 5.883-1.15 7.31-2.853ZM10.436 1.743c1.605 0 3.171.504 4.48 1.44a7.804 7.804 0 0 1 2.829 3.79C16.32 5.272 13.578 4.12 10.438 4.12c-3.14 0-5.884 1.155-7.31 2.855a7.804 7.804 0 0 1 2.828-3.79 7.699 7.699 0 0 1 4.48-1.44ZM3.246 2a.865.865 0 0 1 .91.336.885.885 0 0 1-.062 1.114.869.869 0 0 1-1.433-.224.889.889 0 0 1 .148-.966.875.875 0 0 1 .437-.26ZM16.087.076c.312-.013.617.1.847.313.23.213.367.51.381.824l-.005.176a1.197 1.197 0 0 1-.675.954 1.173 1.173 0 0 1-1.296-.202A1.194 1.194 0 0 1 15.44.305c.188-.14.413-.219.647-.229Z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.6 KiB |
@@ -1,107 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Tutorial: TITLE\n",
|
||||
"\n",
|
||||
"Audience:\n",
|
||||
"- Describe who this is for.\n",
|
||||
"\n",
|
||||
"Prerequisites:\n",
|
||||
"- List required concepts or setup.\n",
|
||||
"\n",
|
||||
"Learning goals:\n",
|
||||
"- By the end, the reader can...\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Outline\n",
|
||||
"\n",
|
||||
"1. Setup\n",
|
||||
"2. A minimal working example\n",
|
||||
"3. Variations and pitfalls\n",
|
||||
"4. Exercises\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Setup cell: keep it short and deterministic\n",
|
||||
"from __future__ import annotations\n",
|
||||
"\n",
|
||||
"import math\n",
|
||||
"import random\n",
|
||||
"\n",
|
||||
"SEED = 21\n",
|
||||
"random.seed(SEED)\n",
|
||||
"SEED\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 1 - Start with a tiny example\n",
|
||||
"\n",
|
||||
"Explain what the next cell does in plain language.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Minimal working example\n",
|
||||
"angles = [0, math.pi / 4, math.pi / 2]\n",
|
||||
"sines = [math.sin(a) for a in angles]\n",
|
||||
"list(zip(angles, sines))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Exercises\n",
|
||||
"\n",
|
||||
"- Try a different input.\n",
|
||||
"- Predict the output before running the code.\n",
|
||||
"- Note one common mistake and how to fix it.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Exercise answer scaffold\n",
|
||||
"def describe(values: list[float]) -> dict[str, float]:\n",
|
||||
" return {\"min\": min(values), \"max\": max(values)}\n",
|
||||
"\n",
|
||||
"describe(sines)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
# Experiment Patterns
|
||||
|
||||
Use this structure for exploratory and experimental work:
|
||||
|
||||
- Title and objective: state the question and the success criteria.
|
||||
- Setup and reproducibility: import only what you need, set a seed early, and keep configuration in one short cell.
|
||||
- Plan: list hypotheses, sweeps, and metrics before running code.
|
||||
- Minimal baseline: start with the smallest runnable example and confirm it runs end-to-end before adding complexity.
|
||||
- Results and notes: summarize findings in markdown near the relevant code and record key metrics in a small dictionary or table-like structure.
|
||||
- Next steps: decide whether to continue, pivot, or stop, and capture follow-up ideas as short bullets.
|
||||
@@ -1,17 +0,0 @@
|
||||
# Notebook Structure
|
||||
|
||||
Jupyter notebooks are JSON documents with this high-level shape:
|
||||
|
||||
- `nbformat` and `nbformat_minor`
|
||||
- `metadata`
|
||||
- `cells` (a list of markdown and code cells)
|
||||
|
||||
When editing `.ipynb` files programmatically:
|
||||
|
||||
- Preserve `nbformat` and `nbformat_minor` from the template.
|
||||
- Keep `cells` as an ordered list; do not reorder unless intentional.
|
||||
- For code cells, set `execution_count` to `null` when unknown.
|
||||
- For code cells, set `outputs` to an empty list when scaffolding.
|
||||
- For markdown cells, keep `cell_type="markdown"` and `metadata={}`.
|
||||
|
||||
Prefer scaffolding from the bundled templates or `new_notebook.py` (for example, `$CODEX_HOME/skills/jupyter-notebook/scripts/new_notebook.py`) instead of hand-authoring raw notebook JSON.
|
||||
@@ -1,11 +0,0 @@
|
||||
# Quality Checklist
|
||||
|
||||
Before delivering a notebook:
|
||||
|
||||
- Run it top-to-bottom at least once (or as much as the environment allows).
|
||||
- Ensure early cells set all required state; avoid hidden state from prior runs.
|
||||
- Keep outputs tidy. Avoid giant outputs when a short summary works.
|
||||
- Prefer small tables, key metrics, or short printouts.
|
||||
- Keep the narrative skimmable. Use headings and short bullets, and avoid long paragraphs.
|
||||
- Leave helpful TODOs only when necessary, and label them clearly.
|
||||
- If execution is not possible, call out the risk and how to validate locally.
|
||||
@@ -1,9 +0,0 @@
|
||||
# Tutorial Patterns
|
||||
|
||||
Use this structure for teaching and walkthroughs:
|
||||
|
||||
- Audience, prerequisites, and learning goals: say who it is for, list what they should already know, and state what they will be able to do by the end.
|
||||
- Outline: provide a short numbered outline so readers can skim.
|
||||
- Step-by-step flow: pair a short markdown explanation with a small code cell that runs on its own and a brief interpretation of the result.
|
||||
- Exercises: include at least one exercise that reinforces the key concept and provide an answer scaffold in the next cell.
|
||||
- Pitfalls and extensions: call out one common mistake and how to fix it, and suggest one optional extension for curious readers.
|
||||
@@ -1,130 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
def slugify(text: str) -> str:
|
||||
lowered = text.strip().lower()
|
||||
cleaned = re.sub(r"[^a-z0-9]+", "-", lowered)
|
||||
collapsed = re.sub(r"-+", "-", cleaned).strip("-")
|
||||
return collapsed or "notebook"
|
||||
|
||||
|
||||
def find_repo_root(start: Path) -> Path:
|
||||
for candidate in (start, *start.parents):
|
||||
if (candidate / ".git").exists():
|
||||
return candidate
|
||||
return start
|
||||
|
||||
|
||||
def load_template(skill_dir: Path, kind: str) -> dict[str, Any]:
|
||||
asset_name = "experiment-template.ipynb" if kind == "experiment" else "tutorial-template.ipynb"
|
||||
template_path = skill_dir / "assets" / asset_name
|
||||
if not template_path.exists():
|
||||
raise SystemExit(f"Missing template: {template_path}")
|
||||
with template_path.open("r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
if not isinstance(data, dict):
|
||||
raise SystemExit(f"Unexpected template shape: {template_path}")
|
||||
return data
|
||||
|
||||
|
||||
def update_title(notebook: dict[str, Any], kind: str, title: str) -> None:
|
||||
prefix = "Experiment" if kind == "experiment" else "Tutorial"
|
||||
expected = f"# {prefix}: {title}\n"
|
||||
|
||||
cells = notebook.get("cells")
|
||||
if not isinstance(cells, list) or not cells:
|
||||
raise SystemExit("Template notebook has no cells")
|
||||
|
||||
first_cell = cells[0]
|
||||
if not isinstance(first_cell, dict) or first_cell.get("cell_type") != "markdown":
|
||||
raise SystemExit("Template notebook must start with a markdown title cell")
|
||||
|
||||
source = first_cell.get("source", [])
|
||||
if isinstance(source, str):
|
||||
source_lines = [source]
|
||||
elif isinstance(source, list):
|
||||
source_lines = [str(line) for line in source]
|
||||
else:
|
||||
source_lines = []
|
||||
|
||||
if source_lines:
|
||||
source_lines[0] = expected
|
||||
else:
|
||||
source_lines = [expected]
|
||||
|
||||
first_cell["source"] = source_lines
|
||||
|
||||
metadata = notebook.setdefault("metadata", {})
|
||||
if not isinstance(metadata, dict):
|
||||
raise SystemExit("Notebook metadata must be a mapping")
|
||||
|
||||
language_info = metadata.setdefault("language_info", {})
|
||||
if isinstance(language_info, dict):
|
||||
language_info.setdefault("name", "python")
|
||||
language_info.setdefault("version", "3.12")
|
||||
|
||||
|
||||
def default_output(repo_root: Path, title: str) -> Path:
|
||||
filename = f"{slugify(title)}.ipynb"
|
||||
return repo_root / "output" / "jupyter-notebook" / filename
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Scaffold a Jupyter notebook for experiments or tutorials.")
|
||||
parser.add_argument(
|
||||
"--kind",
|
||||
choices=["experiment", "tutorial"],
|
||||
default="experiment",
|
||||
help="Notebook style to scaffold (default: experiment).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--title",
|
||||
required=True,
|
||||
help="Human-readable notebook title used in the first markdown cell.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out",
|
||||
type=Path,
|
||||
default=None,
|
||||
help="Output path for the notebook. Defaults to output/jupyter-notebook/<slug>.ipynb.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--force",
|
||||
action="store_true",
|
||||
help="Overwrite the output file if it already exists.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
|
||||
script_path = Path(__file__).resolve()
|
||||
skill_dir = script_path.parents[1]
|
||||
repo_root = find_repo_root(skill_dir)
|
||||
|
||||
notebook = load_template(skill_dir, args.kind)
|
||||
update_title(notebook, args.kind, args.title)
|
||||
|
||||
out_path = args.out or default_output(repo_root, args.title)
|
||||
out_path = out_path.resolve()
|
||||
|
||||
if out_path.exists() and not args.force:
|
||||
raise SystemExit(f"Refusing to overwrite existing file without --force: {out_path}")
|
||||
|
||||
out_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with out_path.open("w", encoding="utf-8") as f:
|
||||
json.dump(notebook, f, indent=2)
|
||||
f.write("\n")
|
||||
|
||||
print(f"Wrote {out_path} using kind={args.kind}.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,98 +0,0 @@
|
||||
---
|
||||
name: proxy-debug
|
||||
description: "Диагностика сетевых проблем и прокси. Вызывай когда пользователь жалуется что не работает сеть, не ходят запросы, проблемы с прокси или VPN, или просит проверить сетевое соединение."
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
# Твоя роль
|
||||
Ты — сетевой диагност. Быстро определяешь, что не так с сетью и прокси.
|
||||
|
||||
# Алгоритм диагностики
|
||||
|
||||
Выполни все проверки и выведи сводную таблицу.
|
||||
|
||||
## 1. Переменные окружения прокси
|
||||
```bash
|
||||
env | grep -i proxy
|
||||
```
|
||||
Проверь что `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, `NO_PROXY` заданы (и lowercase-варианты).
|
||||
|
||||
## 2. Резолв hproxy.local
|
||||
```bash
|
||||
getent hosts hproxy.local
|
||||
```
|
||||
Если не резолвится — прокси недоступен, нужно проверить `/etc/hosts` или DNS.
|
||||
|
||||
## 3. Доступность прокси
|
||||
```bash
|
||||
curl -s --connect-timeout 3 --proxy http://hproxy.local:12334 https://ifconfig.me
|
||||
```
|
||||
```bash
|
||||
curl -s --connect-timeout 3 --proxy socks5://hproxy.local:12334 https://ifconfig.me
|
||||
```
|
||||
|
||||
## 4. Прямое соединение (без прокси)
|
||||
```bash
|
||||
curl -s --connect-timeout 3 --noproxy '*' https://ifconfig.me
|
||||
```
|
||||
|
||||
## 5. DNS-резолв ключевых хостов
|
||||
```bash
|
||||
getent hosts concept-software.ru
|
||||
getent hosts github.com
|
||||
```
|
||||
|
||||
## 6. Git remote
|
||||
```bash
|
||||
git ls-remote --get-url 2>/dev/null
|
||||
git remote -v 2>/dev/null
|
||||
```
|
||||
Если есть remote — проверить `git fetch --dry-run`.
|
||||
|
||||
# Формат вывода
|
||||
|
||||
```
|
||||
Диагностика сети
|
||||
═══════════════════════════════════════
|
||||
|
||||
Прокси-переменные:
|
||||
HTTP_PROXY = http://hproxy.local:12334
|
||||
HTTPS_PROXY = http://hproxy.local:12334
|
||||
ALL_PROXY = socks5://hproxy.local:12334
|
||||
NO_PROXY = hproxy.local,localhost,127.0.0.1,.concept-software.ru
|
||||
⚠️ http_proxy (lowercase) не задан
|
||||
|
||||
Резолв hproxy.local:
|
||||
✅ 172.20.0.1
|
||||
|
||||
Прокси HTTP:
|
||||
✅ работает, внешний IP: 203.0.113.42
|
||||
|
||||
Прокси SOCKS5:
|
||||
✅ работает, внешний IP: 203.0.113.42
|
||||
|
||||
Прямое соединение:
|
||||
❌ таймаут (прокси обязателен)
|
||||
|
||||
DNS:
|
||||
✅ concept-software.ru → 10.0.1.50 (внутренний)
|
||||
✅ github.com → 140.82.121.3
|
||||
|
||||
Git remote:
|
||||
✅ git fetch --dry-run OK
|
||||
|
||||
Итого: сеть работает через прокси. Прямого выхода нет.
|
||||
```
|
||||
|
||||
# Рекомендации по починке
|
||||
|
||||
В зависимости от результатов предложи:
|
||||
- `proxy_on` — если переменные не заданы, но hproxy.local резолвится
|
||||
- Проверить `/etc/hosts` — если hproxy.local не резолвится
|
||||
- Проверить VPN/сетевой адаптер — если ничего не работает
|
||||
- `export NO_PROXY=...` — если внутренний ресурс идёт через прокси когда не должен
|
||||
|
||||
# Правила
|
||||
- Все команды — только чтение и диагностика
|
||||
- Таймауты запросов — не более 3 секунд
|
||||
- Не модифицируй конфигурацию, только предлагай
|
||||
@@ -1,76 +0,0 @@
|
||||
---
|
||||
name: review-homework
|
||||
description: "Ревью кода менти как домашнего задания. Вызывай когда пользователь просит проверить PR менти, отревьюить домашку, дать фидбек на учебный код."
|
||||
disable-model-invocation: true
|
||||
argument-hint: "[PR-номер]"
|
||||
---
|
||||
|
||||
# Твоя роль
|
||||
Ты — наставник (ментор). Ревьюишь код менти в формате обучающего фидбека: не просто указываешь на ошибки, а объясняешь почему и как лучше.
|
||||
|
||||
# Алгоритм действий
|
||||
|
||||
1. **Получи PR:**
|
||||
- `gh pr view $ARGUMENTS --json title,body,baseRefName,headRefName`
|
||||
- `gh pr diff $ARGUMENTS`
|
||||
- Прочитай описание PR — менти мог описать свою логику
|
||||
|
||||
2. **Прочитай изменённые файлы целиком** (не только diff) — контекст важен
|
||||
|
||||
3. **Проведи ревью по чеклисту** (см. ниже)
|
||||
|
||||
4. **Сформируй фидбек** в обучающем формате
|
||||
|
||||
# Чеклист ревью домашки
|
||||
|
||||
## Работоспособность
|
||||
- Код компилируется / запускается без ошибок?
|
||||
- Решает ли поставленную задачу?
|
||||
- Обработаны ли основные edge cases?
|
||||
|
||||
## Читаемость
|
||||
- Понятные имена переменных и функций (не `x`, `temp`, `data2`)
|
||||
- Нет магических чисел — вынесены в константы
|
||||
- Логика разбита на понятные блоки / функции
|
||||
- Комментарии объясняют «зачем», а не «что»
|
||||
|
||||
## Типичные ошибки новичков
|
||||
- Копипаста вместо переиспользования
|
||||
- Глубокая вложенность (if в if в if) — предложи early return
|
||||
- Мутабельное состояние где можно обойтись без него
|
||||
- Игнорирование ошибок (пустой catch, необработанный error)
|
||||
- Хардкод путей, URL, credentials
|
||||
|
||||
## Хорошие практики
|
||||
- Есть ли тесты? Хотя бы базовые?
|
||||
- Разделение ответственности (одна функция — одна задача)
|
||||
- Осмысленные коммиты (или всё одним коммитом?)
|
||||
|
||||
# Формат фидбека
|
||||
|
||||
```markdown
|
||||
## Ревью: <название PR>
|
||||
|
||||
### Что получилось хорошо 👍
|
||||
- [отметь 2-3 удачных решения — это важно для мотивации]
|
||||
|
||||
### Что стоит улучшить 📝
|
||||
- `файл:строка` — **проблема:** описание
|
||||
**почему это важно:** объяснение на простом языке
|
||||
**как лучше:** пример или подсказка (не готовое решение!)
|
||||
|
||||
### На будущее 💡
|
||||
- [1-2 совета, привычки, практики, которые помогут расти]
|
||||
|
||||
### Вердикт
|
||||
✅ Принято / ⚠️ Принято с замечаниями / 🔄 Нужна доработка
|
||||
```
|
||||
|
||||
# Правила тона
|
||||
|
||||
- **Поддерживающий, не снисходительный.** «Хорошая идея, но можно ещё лучше» вместо «это неправильно».
|
||||
- **Обучающий.** Объясняй принцип, не просто давай ответ. Цель — чтобы менти понял и в следующий раз сделал сам.
|
||||
- **Конкретный.** Ссылайся на строки кода, показывай примеры.
|
||||
- **Хвали искренне.** Если менти нашёл элегантное решение — скажи об этом. Не придумывай похвалу если нечего хвалить — менти почувствует фальшь.
|
||||
- **Дозируй.** Не вываливай 20 замечаний — выдели 3-5 самых важных. Остальное можно обсудить позже.
|
||||
- **По умолчанию на русском.** Английский — только с флагом `lang:en`.
|
||||
@@ -1,228 +0,0 @@
|
||||
---
|
||||
name: security-audit
|
||||
description: Audit code and dependencies for security vulnerabilities. Use when reviewing PRs, checking dependencies, preparing for deployment, or when user mentions security, vulnerabilities, or audit.
|
||||
---
|
||||
|
||||
# Security Audit Skill
|
||||
|
||||
Perform comprehensive security audits on codebases to identify vulnerabilities before they reach production.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
- User mentions "security", "audit", "vulnerability", "CVE"
|
||||
- Before deployment commands
|
||||
- During PR reviews
|
||||
- User asks about dependencies
|
||||
- Periodic security checks
|
||||
|
||||
## Audit Checklist
|
||||
|
||||
### 1. Secrets Exposure
|
||||
|
||||
**Check for hardcoded secrets:**
|
||||
```bash
|
||||
# Search for common secret patterns
|
||||
grep -rn "API_KEY\|SECRET\|TOKEN\|PASSWORD" --include="*.{js,ts,py,go,rb,java}" .
|
||||
grep -rn "sk-\|pk_\|api_\|secret_" --include="*.{js,ts,py,go,rb,java}" .
|
||||
```
|
||||
|
||||
**Verify .gitignore:**
|
||||
```bash
|
||||
# Ensure sensitive files are ignored
|
||||
cat .gitignore | grep -E "\.env|secret|credential|\.pem|\.key"
|
||||
```
|
||||
|
||||
**Check git history for leaked secrets:**
|
||||
```bash
|
||||
# Search recent commits (requires git-secrets or truffleHog)
|
||||
git log -p --all -S "API_KEY" --since="30 days ago"
|
||||
```
|
||||
|
||||
✅ Pass criteria:
|
||||
- No hardcoded API keys, tokens, or passwords
|
||||
- `.env` files in `.gitignore`
|
||||
- No secrets in git history
|
||||
|
||||
### 2. Dependency Vulnerabilities
|
||||
|
||||
**Node.js:**
|
||||
```bash
|
||||
npm audit
|
||||
# or
|
||||
yarn audit
|
||||
# or
|
||||
pnpm audit
|
||||
```
|
||||
|
||||
**Python:**
|
||||
```bash
|
||||
pip-audit
|
||||
# or
|
||||
safety check
|
||||
```
|
||||
|
||||
**Go:**
|
||||
```bash
|
||||
govulncheck ./...
|
||||
```
|
||||
|
||||
**Rust:**
|
||||
```bash
|
||||
cargo audit
|
||||
```
|
||||
|
||||
✅ Pass criteria:
|
||||
- No critical vulnerabilities
|
||||
- No high vulnerabilities > 30 days old
|
||||
- Dependencies updated within last 90 days
|
||||
|
||||
### 3. Input Validation
|
||||
|
||||
**Check for:**
|
||||
- User inputs sanitized before use
|
||||
- SQL queries use parameterized statements
|
||||
- File paths validated and sandboxed
|
||||
- HTML content escaped before rendering
|
||||
- Command injection prevention
|
||||
|
||||
**Common vulnerable patterns:**
|
||||
```javascript
|
||||
// BAD: SQL injection
|
||||
db.query(`SELECT * FROM users WHERE id = ${userId}`)
|
||||
|
||||
// GOOD: Parameterized query
|
||||
db.query('SELECT * FROM users WHERE id = ?', [userId])
|
||||
```
|
||||
|
||||
```python
|
||||
# BAD: Command injection
|
||||
os.system(f"convert {user_file}")
|
||||
|
||||
# GOOD: Use subprocess with list
|
||||
subprocess.run(["convert", user_file], check=True)
|
||||
```
|
||||
|
||||
### 4. Authentication & Authorization
|
||||
|
||||
**Check for:**
|
||||
- Passwords hashed with bcrypt/argon2 (not MD5/SHA1)
|
||||
- Session tokens are cryptographically random
|
||||
- Sessions expire appropriately
|
||||
- CSRF protection on state-changing endpoints
|
||||
- Rate limiting on auth endpoints
|
||||
- Account lockout after failed attempts
|
||||
|
||||
**Look for:**
|
||||
```javascript
|
||||
// BAD: Weak hashing
|
||||
crypto.createHash('md5').update(password)
|
||||
|
||||
// GOOD: Bcrypt
|
||||
bcrypt.hash(password, 12)
|
||||
```
|
||||
|
||||
### 5. HTTPS & Transport Security
|
||||
|
||||
**Check for:**
|
||||
- HTTPS enforced (HSTS header)
|
||||
- Secure cookie flags (`Secure`, `HttpOnly`, `SameSite`)
|
||||
- No mixed content warnings
|
||||
- TLS 1.2+ required
|
||||
|
||||
### 6. Error Handling
|
||||
|
||||
**Check for:**
|
||||
- Stack traces not exposed in production
|
||||
- Generic error messages for users
|
||||
- Detailed errors only in logs
|
||||
- Sensitive data not in error messages
|
||||
|
||||
```javascript
|
||||
// BAD: Exposes internals
|
||||
res.status(500).send({ error: err.stack })
|
||||
|
||||
// GOOD: Generic message
|
||||
res.status(500).send({ error: 'An unexpected error occurred' })
|
||||
```
|
||||
|
||||
### 7. File Upload Security
|
||||
|
||||
If file uploads exist:
|
||||
- Validate file type server-side (not just extension)
|
||||
- Limit file size
|
||||
- Scan for malware
|
||||
- Store outside webroot
|
||||
- Rename uploaded files
|
||||
|
||||
### 8. API Security
|
||||
|
||||
- Authentication required on all sensitive endpoints
|
||||
- Authorization checks per resource
|
||||
- Rate limiting implemented
|
||||
- CORS configured restrictively
|
||||
- API versioning in place
|
||||
|
||||
## Severity Levels
|
||||
|
||||
| Level | Description | Action Required |
|
||||
|-------|-------------|-----------------|
|
||||
| 🔴 Critical | Actively exploitable | Block deployment |
|
||||
| 🟠 High | Exploitable with effort | Fix within 7 days |
|
||||
| 🟡 Medium | Requires conditions | Fix within 30 days |
|
||||
| 🟢 Low | Minimal impact | Fix when convenient |
|
||||
|
||||
## Output Format
|
||||
|
||||
```markdown
|
||||
## Security Audit Results
|
||||
|
||||
**Project:** [name]
|
||||
**Date:** [date]
|
||||
**Auditor:** Claude (automated)
|
||||
|
||||
### Summary
|
||||
|
||||
| Severity | Count |
|
||||
|----------|-------|
|
||||
| 🔴 Critical | 0 |
|
||||
| 🟠 High | 1 |
|
||||
| 🟡 Medium | 2 |
|
||||
| 🟢 Low | 3 |
|
||||
|
||||
### Findings
|
||||
|
||||
#### 1. [🟠 High] Hardcoded API Key
|
||||
|
||||
**Location:** `src/config.js:15`
|
||||
**Description:** API key for payment provider is hardcoded
|
||||
**Risk:** If source code is leaked, attackers gain API access
|
||||
**Recommendation:** Move to environment variable
|
||||
|
||||
```diff
|
||||
- const STRIPE_KEY = 'sk_live_abc123...'
|
||||
+ const STRIPE_KEY = process.env.STRIPE_SECRET_KEY
|
||||
```
|
||||
|
||||
#### 2. [🟡 Medium] Missing Rate Limiting
|
||||
|
||||
**Location:** `src/routes/auth.js`
|
||||
**Description:** Login endpoint has no rate limiting
|
||||
**Risk:** Enables brute force attacks
|
||||
**Recommendation:** Add rate limiting middleware
|
||||
|
||||
### Recommendations
|
||||
|
||||
1. [ ] Fix critical and high issues before next deployment
|
||||
2. [ ] Schedule medium issues for next sprint
|
||||
3. [ ] Add low issues to backlog
|
||||
4. [ ] Re-run audit after fixes
|
||||
```
|
||||
|
||||
## Commands to Run
|
||||
|
||||
After completing the audit, provide the user with:
|
||||
|
||||
1. Summary of findings
|
||||
2. Prioritized fix list
|
||||
3. Commands to address each issue
|
||||
4. Timeline recommendation
|
||||
Reference in new issue
Block a user