diff --git a/agents/.agents/skills/docstring/SKILL.md b/agents/.agents/skills/docstring/SKILL.md
deleted file mode 100644
index 292b571..0000000
--- a/agents/.agents/skills/docstring/SKILL.md
+++ /dev/null
@@ -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 |
-
diff --git a/agents/.agents/skills/dotfiles-check/SKILL.md b/agents/.agents/skills/dotfiles-check/SKILL.md
deleted file mode 100644
index 98a5750..0000000
--- a/agents/.agents/skills/dotfiles-check/SKILL.md
+++ /dev/null
@@ -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) — кратко прокомментируй что сломалось и предложи команды для починки.
diff --git a/agents/.agents/skills/dotfiles-check/check.sh b/agents/.agents/skills/dotfiles-check/check.sh
deleted file mode 100755
index 24c21cb..0000000
--- a/agents/.agents/skills/dotfiles-check/check.sh
+++ /dev/null
@@ -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
diff --git a/agents/.agents/skills/jupyter-notebook/LICENSE.txt b/agents/.agents/skills/jupyter-notebook/LICENSE.txt
deleted file mode 100644
index 13e25df..0000000
--- a/agents/.agents/skills/jupyter-notebook/LICENSE.txt
+++ /dev/null
@@ -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.
diff --git a/agents/.agents/skills/jupyter-notebook/SKILL.md b/agents/.agents/skills/jupyter-notebook/SKILL.md
deleted file mode 100644
index e1d1748..0000000
--- a/agents/.agents/skills/jupyter-notebook/SKILL.md
+++ /dev/null
@@ -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.
diff --git a/agents/.agents/skills/jupyter-notebook/agents/openai.yaml b/agents/.agents/skills/jupyter-notebook/agents/openai.yaml
deleted file mode 100644
index 8832dea..0000000
--- a/agents/.agents/skills/jupyter-notebook/agents/openai.yaml
+++ /dev/null
@@ -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."
diff --git a/agents/.agents/skills/jupyter-notebook/assets/experiment-template.ipynb b/agents/.agents/skills/jupyter-notebook/assets/experiment-template.ipynb
deleted file mode 100644
index a4a0323..0000000
--- a/agents/.agents/skills/jupyter-notebook/assets/experiment-template.ipynb
+++ /dev/null
@@ -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
-}
diff --git a/agents/.agents/skills/jupyter-notebook/assets/jupyter-small.svg b/agents/.agents/skills/jupyter-notebook/assets/jupyter-small.svg
deleted file mode 100644
index 472d07f..0000000
--- a/agents/.agents/skills/jupyter-notebook/assets/jupyter-small.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/agents/.agents/skills/jupyter-notebook/assets/jupyter.png b/agents/.agents/skills/jupyter-notebook/assets/jupyter.png
deleted file mode 100644
index 51cdf7d..0000000
Binary files a/agents/.agents/skills/jupyter-notebook/assets/jupyter.png and /dev/null differ
diff --git a/agents/.agents/skills/jupyter-notebook/assets/tutorial-template.ipynb b/agents/.agents/skills/jupyter-notebook/assets/tutorial-template.ipynb
deleted file mode 100644
index 7001309..0000000
--- a/agents/.agents/skills/jupyter-notebook/assets/tutorial-template.ipynb
+++ /dev/null
@@ -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
-}
diff --git a/agents/.agents/skills/jupyter-notebook/references/experiment-patterns.md b/agents/.agents/skills/jupyter-notebook/references/experiment-patterns.md
deleted file mode 100644
index 2d5093b..0000000
--- a/agents/.agents/skills/jupyter-notebook/references/experiment-patterns.md
+++ /dev/null
@@ -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.
diff --git a/agents/.agents/skills/jupyter-notebook/references/notebook-structure.md b/agents/.agents/skills/jupyter-notebook/references/notebook-structure.md
deleted file mode 100644
index 681d36f..0000000
--- a/agents/.agents/skills/jupyter-notebook/references/notebook-structure.md
+++ /dev/null
@@ -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.
diff --git a/agents/.agents/skills/jupyter-notebook/references/quality-checklist.md b/agents/.agents/skills/jupyter-notebook/references/quality-checklist.md
deleted file mode 100644
index 5482f28..0000000
--- a/agents/.agents/skills/jupyter-notebook/references/quality-checklist.md
+++ /dev/null
@@ -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.
diff --git a/agents/.agents/skills/jupyter-notebook/references/tutorial-patterns.md b/agents/.agents/skills/jupyter-notebook/references/tutorial-patterns.md
deleted file mode 100644
index 2a360b0..0000000
--- a/agents/.agents/skills/jupyter-notebook/references/tutorial-patterns.md
+++ /dev/null
@@ -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.
diff --git a/agents/.agents/skills/jupyter-notebook/scripts/new_notebook.py b/agents/.agents/skills/jupyter-notebook/scripts/new_notebook.py
deleted file mode 100644
index 0aba209..0000000
--- a/agents/.agents/skills/jupyter-notebook/scripts/new_notebook.py
+++ /dev/null
@@ -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/.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()
diff --git a/agents/.agents/skills/proxy-debug/SKILL.md b/agents/.agents/skills/proxy-debug/SKILL.md
deleted file mode 100644
index e3b0609..0000000
--- a/agents/.agents/skills/proxy-debug/SKILL.md
+++ /dev/null
@@ -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 секунд
-- Не модифицируй конфигурацию, только предлагай
diff --git a/agents/.agents/skills/review-homework/SKILL.md b/agents/.agents/skills/review-homework/SKILL.md
deleted file mode 100644
index d2be228..0000000
--- a/agents/.agents/skills/review-homework/SKILL.md
+++ /dev/null
@@ -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`.
diff --git a/agents/.agents/skills/security-audit/SKILL.md b/agents/.agents/skills/security-audit/SKILL.md
deleted file mode 100644
index 2b7e179..0000000
--- a/agents/.agents/skills/security-audit/SKILL.md
+++ /dev/null
@@ -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