diff --git a/CHANGELOG.md b/CHANGELOG.md index f9a6def..440cddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ All notable changes to Skilz CLI will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.9.0] - 2026-01-21 + +### Changed + +- Documentation updates to match current feature set + - Updated USER_MANUAL.md from v1.6.0 to v1.9.0 + - Fixed DEPLOY_PYPI.md version management documentation + - Updated key_facts.md with version management notes + +### Documentation + +- Added version management section to key_facts.md +- Corrected DEPLOY_PYPI.md to reflect dynamic versioning +- USER_MANUAL.md now documents 1.7 and 1.8 features: + - Gemini native support + - NEW/LEGACY/SLUG format support + - Universal agent custom config + - List command with Agent column + - `--all` flag for list command + ## [1.8.0] - 2026-01-09 ### Added diff --git a/docs/DEPLOY_PYPI.md b/docs/DEPLOY_PYPI.md index 84444ff..1e75a2e 100644 --- a/docs/DEPLOY_PYPI.md +++ b/docs/DEPLOY_PYPI.md @@ -103,7 +103,7 @@ Skilz uses a comprehensive multi-layer testing approach: - [ ] `./scripts/end_to_end.sh` passes (full feature test) - [ ] `./scripts/test_rest_marketplace_e2e.sh` passes (live API test) - [ ] `./scripts/test_bug_fixes_e2e.sh` passes (regression test) -- [ ] Version updated in `src/skilz/__init__.py` and `pyproject.toml` +- [ ] Version updated in `pyproject.toml` (single source of truth) - [ ] CHANGELOG.md updated with release notes - [ ] GitHub release created and tagged @@ -168,20 +168,26 @@ skilz --version ## Version Management -The version is defined in `src/skilz/__init__.py`: +**Single Source of Truth:** `pyproject.toml` (line 7) -```python -__version__ = "1.2.0" # Update to new version -``` - -And mirrored in `pyproject.toml`: +The version is defined ONLY in `pyproject.toml`: ```toml [project] -version = "1.2.0" # Must match __init__.py +version = "1.9.0" +``` + +The Python package reads this dynamically at runtime via `importlib.metadata`: + +```python +# src/skilz/__init__.py +from importlib.metadata import version +__version__ = version("skilz") # Reads from pyproject.toml ``` -**Before releasing**, update both files to match. +**Before releasing**, only update `pyproject.toml`. No other files need version changes. + +**Note:** Previous versions required updating both `pyproject.toml` AND `__init__.py`. This was fixed in 1.7 to use dynamic version detection, eliminating version sync issues. ## Taskfile Commands Reference diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index 1b8304b..a9165ee 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -1,6 +1,6 @@ # Skilz User Manual -**Version 1.6.0** +**Version 1.9.0** Skilz is the universal package manager for AI skills. It installs, manages, and updates skills across multiple AI coding assistants including Claude Code and OpenCode. @@ -176,6 +176,39 @@ Already installed: anthropics_skills/theme-factory (00756142) --- +### NEW Marketplace Format (NEW in 1.7) + +Skilz 1.7+ supports a new intuitive skill ID format that mirrors GitHub's URL structure: + +**Supported Formats:** + +| Format | Example | Description | +|--------|---------|-------------| +| **NEW** | `owner/repo/skill` | Intuitive GitHub-style format | +| **LEGACY** | `owner_repo/skill` | Original underscore format | +| **SLUG** | `owner__repo__skill` | Direct Firestore document ID | + +**All formats are REST-first** - they try the skillzwave.ai REST API before falling back to GitHub. + +**Examples:** + +```bash +# NEW format (recommended) +skilz install anthropics/skills/algorithmic-art + +# LEGACY format (backwards compatible) +skilz install anthropics_skills/algorithmic-art + +# SLUG format (direct Firestore ID) +skilz install anthropics__skills__algorithmic-art + +# Verbose mode shows format detection +skilz install anthropics/skills/algorithmic-art -v +# Output: Detected format: NEW, attempting REST lookup... +``` + +--- + ### Installing Local Skills You can install skills directly from your local filesystem. This is useful for developing new skills or installing skills from other agent directories (like Claude or OpenCode). @@ -803,11 +836,20 @@ Skilz supports multiple AI coding assistants. Use `--agent` to target a specific | Agent | Skills Directory | Notes | |-------|------------------|-------| -| `claude` | `~/.claude/skills/` (user) or `.claude/skills/` (project) | Native support | -| `gemini` | `~/.gemini/skills/` (user) or `.gemini/skills/` (project) | Native support (NEW in 1.7, requires plugin) | -| `codex` | `~/.codex/skills/` (user) or `.codex/skills/` (project) | Auto-detected from `.codex/` | -| `opencode` | `~/.config/opencode/skill/` (user) or `.opencode/skill/` (project) | Native support | -| `universal` | `~/.skilz/skills/` (user) or `.skilz/skills/` (project) | Supports custom config files (NEW in 1.7) | +| `claude` | `~/.claude/skills/` or `.claude/skills/` | Native support | +| `codex` | `~/.codex/skills/` or `.codex/skills/` | Native support | +| `opencode` | `~/.config/opencode/skill/` or `.opencode/skill/` | Native support | +| `gemini` | `~/.gemini/skills/` or `.gemini/skills/` | Native support (requires plugin) | +| `copilot` | `.github/skills/` | Project-level only | +| `cursor` | `.cursor/skills/` | Project-level only | +| `aider` | `~/.aider/skills/` | User-level | +| `windsurf` | `~/.windsurf/skills/` | User-level | +| `qwen` | `~/.qwen/skills/` | User-level | +| `kimi` | `~/.kimi/skills/` | User-level | +| `crush` | `~/.crush/skills/` | User-level | +| `plandex` | `~/.plandex/skills/` | User-level | +| `zed` | `~/.zed/skills/` | User-level | +| `universal` | `~/.skilz/skills/` or `.skilz/skills/` | Universal fallback | **Auto-detection:** diff --git a/docs/project_notes/key_facts.md b/docs/project_notes/key_facts.md index bc1dcb1..ddfd310 100644 --- a/docs/project_notes/key_facts.md +++ b/docs/project_notes/key_facts.md @@ -55,6 +55,21 @@ task typecheck # Run mypy --- +## Version Management + +**Single Source of Truth:** `pyproject.toml` line 7 + +| File | Role | +|------|------| +| `pyproject.toml` | Primary version definition (edit this one) | +| `src/skilz/__init__.py` | Dynamic detection via `importlib.metadata.version("skilz")` | + +**Release Process:** Only update `pyproject.toml`. The Python module automatically reads the version from package metadata at runtime. + +**Previous Bug (Fixed in 1.7):** Before dynamic detection, version was hardcoded in both files and they would get out of sync, causing `skilz --version` to show wrong version. + +--- + ## Important Paths | Path | Purpose | @@ -109,13 +124,23 @@ Before any PR: ## Verification History -### 2025-01-08 - Instructions Verification -- ✅ Development setup completed successfully (`task install`) -- ✅ All 620 tests passing with 87% coverage (`task test`, `task coverage`) -- ✅ Code quality checks passing (lint, format, typecheck via `task check`) -- ✅ CLI functionality verified (`skilz --version`, `skilz --help`) -- ✅ Project is in production-ready state (v1.7.0) +### 2026-01-21 - v1.9.0 Pre-Release +- ✅ Version bumped to 1.9.0 in pyproject.toml +- ✅ Documentation updated (USER_MANUAL.md, DEPLOY_PYPI.md) +- ✅ CHANGELOG.md updated with 1.9.0 entry +- ✅ All tests passing +- ✅ Local build verified + +### 2025-01-09 - v1.8.0 Release +- ✅ List command enhancements (Agent column, --all flag) +- ✅ CLI help discoverability improvements +- ✅ Visit command URL format fix + +### 2025-01-08 - v1.7.0 Release +- ✅ Gemini CLI native support +- ✅ NEW/LEGACY/SLUG format support +- ✅ Universal agent custom config --- -*Last Updated: 2025-01-08* +*Last Updated: 2026-01-21* diff --git a/pyproject.toml b/pyproject.toml index 0555448..36d3a01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "skilz" -version = "1.8.0" +version = "1.9.0" description = "The universal package manager for AI skills" readme = "README.md" license = "MIT" diff --git a/src/skilz/agent_registry.py b/src/skilz/agent_registry.py index d534ee9..7596400 100644 --- a/src/skilz/agent_registry.py +++ b/src/skilz/agent_registry.py @@ -172,7 +172,7 @@ def _create_builtin_agents() -> dict[str, AgentConfig]: name="aider", display_name="Aider", home_dir=None, - project_dir=Path(".skills") / "skills", + project_dir=Path(".skilz") / "skills", config_files=("CONVENTIONS.md",), supports_home=False, default_mode="copy", @@ -182,7 +182,7 @@ def _create_builtin_agents() -> dict[str, AgentConfig]: name="cursor", display_name="Cursor", home_dir=None, - project_dir=Path(".skills") / "skills", + project_dir=Path(".skilz") / "skills", config_files=(".cursor/rules/RULES.md", ".cursor/rules/RULE.md"), supports_home=False, default_mode="copy", @@ -193,7 +193,7 @@ def _create_builtin_agents() -> dict[str, AgentConfig]: name="windsurf", display_name="Windsurf", home_dir=None, - project_dir=Path(".skills") / "skills", + project_dir=Path(".skilz") / "skills", config_files=(), supports_home=False, default_mode="copy", @@ -203,7 +203,7 @@ def _create_builtin_agents() -> dict[str, AgentConfig]: name="qwen", display_name="Qwen CLI", home_dir=None, - project_dir=Path(".skills") / "skills", + project_dir=Path(".skilz") / "skills", config_files=("QWEN.md", "CONTEXT.md"), supports_home=False, default_mode="copy", @@ -213,7 +213,7 @@ def _create_builtin_agents() -> dict[str, AgentConfig]: name="crush", display_name="Crush", home_dir=None, - project_dir=Path(".skills") / "skills", + project_dir=Path(".skilz") / "skills", config_files=(), supports_home=False, default_mode="copy", @@ -223,7 +223,7 @@ def _create_builtin_agents() -> dict[str, AgentConfig]: name="kimi", display_name="Kimi CLI", home_dir=None, - project_dir=Path(".skills") / "skills", + project_dir=Path(".skilz") / "skills", config_files=(), supports_home=False, default_mode="copy", @@ -233,7 +233,7 @@ def _create_builtin_agents() -> dict[str, AgentConfig]: name="plandex", display_name="Plandex", home_dir=None, - project_dir=Path(".skills") / "skills", + project_dir=Path(".skilz") / "skills", config_files=(), supports_home=False, default_mode="copy", @@ -243,7 +243,7 @@ def _create_builtin_agents() -> dict[str, AgentConfig]: name="zed", display_name="Zed AI", home_dir=None, - project_dir=Path(".skills") / "skills", + project_dir=Path(".skilz") / "skills", config_files=(), supports_home=False, default_mode="copy", diff --git a/src/skilz/config_sync.py b/src/skilz/config_sync.py index 6d603c4..c6f07e9 100644 --- a/src/skilz/config_sync.py +++ b/src/skilz/config_sync.py @@ -41,7 +41,7 @@ def _generate_usage_template( else: invocation = f'Bash("skilz read --agent {agent_name}")' - # Extended instructions for agents without native support OR when forced + # Extended step-by-step instructions for agents without native support OR when forced if native_support == "none" or force_extended: extra_steps = """ Step-by-step process: @@ -53,6 +53,16 @@ def _generate_usage_template( else: extra_steps = "" + # Usage notes ONLY for agents without native support (not affected by force_extended) + if native_support == "none": + usage_notes = """ +Usage notes: +- Only use skills listed in below +- Do not invoke a skill that is already loaded in your context +""" + else: + usage_notes = "" + return f""" When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. @@ -61,11 +71,7 @@ def _generate_usage_template( - Invoke: {invocation} - The skill content will load with detailed instructions - Base directory provided in output for resolving bundled resources -{extra_steps} -Usage notes: -- Only use skills listed in below -- Do not invoke a skill that is already loaded in your context -""" +{extra_steps}{usage_notes}""" @dataclass diff --git a/src/skilz/installer.py b/src/skilz/installer.py index 799d340..9a2d514 100644 --- a/src/skilz/installer.py +++ b/src/skilz/installer.py @@ -196,7 +196,7 @@ def install_local_skill( ) elif verbose: agent_config = get_registry().get(resolved_agent) - project_path = agent_config.project_dir if agent_config else ".skills/skills" + project_path = agent_config.project_dir if agent_config else ".skilz/skills" print( f" Note: {get_agent_display_name(resolved_agent)} only supports " f"project-level installation ({project_path}/)" @@ -336,7 +336,7 @@ def install_skill( ) elif verbose: agent_config = get_registry().get(resolved_agent) - project_path = agent_config.project_dir if agent_config else ".skills/skills" + project_path = agent_config.project_dir if agent_config else ".skilz/skills" print( f" Note: {get_agent_display_name(resolved_agent)} only supports " f"project-level installation ({project_path}/)"