gem-skill 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e537a3925c494c903dc9dd105d6a975d55d5fe55f963847cca3c363ce26120d6
4
- data.tar.gz: 7f4fd4cff99d062ab50bf73b733aeddca903f23ffb657ccc7cc7616dcd7e2fe6
3
+ metadata.gz: 81806de91a59a0b2f9144dedebda65f568d61629064f6182f753229fced49583
4
+ data.tar.gz: 444441e8f081192ceb5b6201bc8c2c9428b243729df896a4405db562d435ad7d
5
5
  SHA512:
6
- metadata.gz: 2d74ee4cdbf3b827984574580985426ec708e7dfd901f2ddb99f03268afdcc96a2ab9f8962781549c053e587f1ecbd4f0d5cab06189adb24603af475083ab54e
7
- data.tar.gz: e012f26a513a5516d606c6664c1ccd470ed910bd57190850e96daf1bc88e686e00dfbfc2b6f9bd8a467bdde6d5ca938b3084697ca27d2a956043b05e9d8dac37
6
+ metadata.gz: 39ed27eb70e0036d097b01576a78a20a13ed337ddf05abfc5f5a63a0279b65c79d327907cc70fa96d132d7e72ae3d47ce5cdb5a0bb50e30cbfbb441ce428611d
7
+ data.tar.gz: 6c0fd5f43ffeac14efe923f9b1742ab469d3e08c50f86dd521c38d45d003800fe45a8447dcb682df0014419d1421d1b2f20eb326d3b6c7f2d3b1d7d0210974bb
@@ -0,0 +1,52 @@
1
+ name: Deploy Documentation to GitHub Pages
2
+ on:
3
+ push:
4
+ branches:
5
+ - main
6
+ - develop
7
+ paths:
8
+ - "docs/**"
9
+ - "mkdocs.yml"
10
+ - ".github/workflows/deploy-github-pages.yml"
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: write
15
+ pages: write
16
+ id-token: write
17
+
18
+ jobs:
19
+ deploy:
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - name: Checkout code
23
+ uses: actions/checkout@v4
24
+ with:
25
+ fetch-depth: 0
26
+
27
+ - name: Setup Python
28
+ uses: actions/setup-python@v5
29
+ with:
30
+ python-version: 3.x
31
+
32
+ - name: Install dependencies
33
+ run: |
34
+ pip install mkdocs
35
+ pip install mkdocs-material
36
+ pip install mkdocs-macros-plugin
37
+ pip install mike
38
+
39
+ - name: Configure Git
40
+ run: |
41
+ git config --local user.email "action@github.com"
42
+ git config --local user.name "GitHub Action"
43
+
44
+ - name: Deploy to GitHub Pages
45
+ run: |
46
+ if [ "${{ github.ref }}" = "refs/heads/main" ]; then
47
+ echo "Deploying from main branch"
48
+ mkdocs gh-deploy --force --clean
49
+ else
50
+ echo "Deploying from develop branch"
51
+ mkdocs gh-deploy --force --clean
52
+ fi
data/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
+ # Changelog
2
+
3
+ All notable changes to gem-skill are documented here.
4
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
+
1
6
  ## [Unreleased]
2
7
 
8
+ ## [0.1.3] - 2026-06-17
9
+
10
+ ### Added
11
+ - `gem skill setup` subcommand — registers gem-skill as a Bundler plugin in one step
12
+ - `--version` / `-v` flag for both `gem skill` and `bundle skill`
13
+ - `post_install_message` guiding users to run `gem skill setup` after install
14
+ - `async` gem dependency — concurrent fiber-based LLM calls replace threads
15
+ - `Gem::Skill::Runner` module — shared `install_skill` core extracted from both CLI commands
16
+ - `test/support/cache_helpers.rb` — shared `stub_cache_root`/`restore_cache_root` test helpers
17
+ - MkDocs documentation site (`docs/`) with full reference for all commands, cache layout, skill file format, and architecture
18
+
19
+ ### Changed
20
+ - `bundle skill install` and `bundle skill refresh` now run all gems concurrently via `Async::Barrier` (previously sequential)
21
+ - `gem skill install` also migrated from threads to async fibers
22
+ - `Lockfile.gems` now includes runtime dependencies declared in gemspec files (via `gemspec` in `Gemfile`), not just direct `Gemfile` entries
23
+ - `.claude/skills/` symlinks now point to version directories (e.g. `~/.gem/skills/faraday/2.14.3/`) instead of individual `SKILL.md` files
24
+ - `GEMSKILL_DIR` environment variable controls the cache root (default: `~/.gem/skills`)
25
+ - `GEMSKILL_MODEL` environment variable controls the default LLM model
26
+ - `scripts/e2e_test` updated to exercise the full pipeline: Fetch → Runner → Cache → Linker
27
+
28
+ ### Removed
29
+ - `thor` runtime dependency (was declared but never used)
30
+
3
31
  ## [0.1.0] - 2026-06-16
4
32
 
5
33
  - Initial release
data/README.md CHANGED
@@ -1,7 +1,18 @@
1
1
  # gem-skill
2
2
 
3
- Generates Claude Code skill files from Ruby gem documentation and caches them
4
- globally so every project that uses a gem can share the same pre-built knowledge.
3
+ <p align="center">
4
+ <table style="width:38%;margin:0 auto;" border="0" cellpadding="8">
5
+ <tr>
6
+ <td width="40%"><img src="docs/assets/images/gem-skill.jpg" alt="gem-skill logo" width="100%"></td>
7
+ <td width="60%">
8
+ Generate Claude Code skill files from Ruby gem
9
+ documentation and caches them globally so every project that uses a gem
10
+ can share the same pre-built knowledge.<br><br>
11
+ <strong><a href="https://madbomber.github.io/gem-skill">Full documentation →</a></strong>
12
+ </td>
13
+ </tr>
14
+ </table>
15
+ </p>
5
16
 
6
17
  ## The problem it solves
7
18
 
@@ -110,6 +121,9 @@ gem skill purge chunker-ruby 1.2.3
110
121
 
111
122
  # Remove all cached versions of a gem
112
123
  gem skill purge chunker-ruby --all
124
+
125
+ # Print the installed version
126
+ gem skill --version
113
127
  ```
114
128
 
115
129
  If a gem isn't installed locally, `gem skill install` will install it first.
@@ -151,6 +165,9 @@ bundle skill list
151
165
  # Options available on install and refresh
152
166
  bundle skill install --force
153
167
  bundle skill install --model claude-haiku-4-5
168
+
169
+ # Print the installed version
170
+ bundle skill --version
154
171
  ```
155
172
 
156
173
  ## What gets generated
Binary file
data/docs/cache.md ADDED
@@ -0,0 +1,108 @@
1
+ # Cache
2
+
3
+ ## Location
4
+
5
+ The global skill cache lives at `~/.gem/skills` by default. Override with:
6
+
7
+ ```bash
8
+ export GEMSKILL_DIR="/path/to/your/cache"
9
+ ```
10
+
11
+ ## Structure
12
+
13
+ ```
14
+ ~/.gem/skills/
15
+ ├── debug_me/
16
+ │ └── 1.1.0/
17
+ │ ├── SKILL.md
18
+ │ └── metadata.json
19
+ ├── faraday/
20
+ │ ├── 2.12.0/
21
+ │ │ ├── SKILL.md
22
+ │ │ └── metadata.json
23
+ │ └── 2.14.3/
24
+ │ ├── SKILL.md
25
+ │ └── metadata.json
26
+ └── zeitwerk/
27
+ └── 2.8.2/
28
+ ├── SKILL.md
29
+ └── metadata.json
30
+ ```
31
+
32
+ Each gem can have multiple cached versions. They coexist without conflict — two
33
+ projects pinning different versions of the same gem each get the correct skill.
34
+
35
+ ## Files
36
+
37
+ ### `SKILL.md`
38
+
39
+ The generated skill file. Contains structured documentation tailored for
40
+ Claude Code. See [Skill Files](skill-files.md) for the format.
41
+
42
+ ### `metadata.json`
43
+
44
+ Stores provenance information:
45
+
46
+ ```json
47
+ {
48
+ "gem_name": "faraday",
49
+ "version": "2.14.3",
50
+ "model": "claude-sonnet-4-6",
51
+ "generated_at": "2026-06-17T10:23:45Z",
52
+ "sources": ["readme", "changelog", "rubygems"]
53
+ }
54
+ ```
55
+
56
+ ## Cache commands
57
+
58
+ ```bash
59
+ # List everything in the cache
60
+ gem skill list
61
+
62
+ # Remove a specific version
63
+ gem skill purge faraday 2.12.0
64
+
65
+ # Remove all versions of a gem
66
+ gem skill purge faraday --all
67
+ ```
68
+
69
+ ## Sharing the cache
70
+
71
+ You can share a skill cache across machines by pointing `GEMSKILL_DIR` at a
72
+ shared location:
73
+
74
+ ```bash
75
+ # Team-shared network drive
76
+ export GEMSKILL_DIR="/Volumes/team-shared/gem-skills"
77
+ ```
78
+
79
+ All machines with the same `GEMSKILL_DIR` will read and write to the same cache.
80
+ Skills generated on one machine are immediately available on others.
81
+
82
+ ## Project symlinks
83
+
84
+ Projects don't store skills locally — they hold symlinks into the global cache:
85
+
86
+ ```
87
+ your-project/.claude/skills/
88
+ ├── faraday → ~/.gem/skills/faraday/2.14.3/
89
+ └── zeitwerk → ~/.gem/skills/zeitwerk/2.8.2/
90
+ ```
91
+
92
+ Each symlink points to the **version directory**. Claude Code reads `SKILL.md`
93
+ from inside the linked directory.
94
+
95
+ `bundle skill refresh` updates symlinks when versions change after `bundle update`.
96
+ `bundle skill list` shows the status of all current symlinks.
97
+
98
+ ## Regenerating skills
99
+
100
+ Skills do not auto-expire. Regenerate explicitly when you want updated content:
101
+
102
+ ```bash
103
+ # Regenerate one gem
104
+ gem skill install faraday --force
105
+
106
+ # Regenerate all project gems with a better model
107
+ bundle skill install --force --model claude-opus-4-8
108
+ ```
@@ -0,0 +1,147 @@
1
+ # bundle skill
2
+
3
+ The `bundle skill` command is project-aware: it reads `Gemfile.lock` to
4
+ determine which gems and versions are in use, generates skills for all of them,
5
+ and links the results into `.claude/skills/` in the project root.
6
+
7
+ ## Global options
8
+
9
+ These flags work without a subcommand:
10
+
11
+ ```bash
12
+ bundle skill --version # print installed version and exit
13
+ bundle skill -v # same
14
+ ```
15
+
16
+ ## Prerequisites
17
+
18
+ Run once after installing gem-skill:
19
+
20
+ ```bash
21
+ gem skill setup
22
+ ```
23
+
24
+ Or add to the project `Gemfile`:
25
+
26
+ ```ruby
27
+ plugin "gem-skill"
28
+ ```
29
+
30
+ ## Subcommands
31
+
32
+ ### `bundle skill install`
33
+
34
+ Generate and link skills for all direct dependencies in `Gemfile.lock`.
35
+
36
+ ```bash
37
+ bundle skill install [OPTIONS]
38
+ ```
39
+
40
+ **Options:**
41
+
42
+ | Flag | Description |
43
+ |------|-------------|
44
+ | `--force` | Regenerate even if skills are already cached |
45
+ | `--model MODEL` | LLM model to use (overrides `GEMSKILL_MODEL`) |
46
+ | `--version`, `-v` | Print the installed gem-skill version and exit |
47
+
48
+ **Example:**
49
+
50
+ ```bash
51
+ cd your-project
52
+ bundle skill install
53
+ ```
54
+
55
+ **What it processes:**
56
+
57
+ - All gems listed in the `DEPENDENCIES` section of `Gemfile.lock`
58
+ - Runtime dependencies declared in any `gemspec` referenced by the `Gemfile` (via `gemspec` directive)
59
+
60
+ All gems are processed concurrently:
61
+
62
+ ```
63
+ ⠋ Installing skills (claude-sonnet-4-6)
64
+ ✓ rake 13.4.2 already cached
65
+ ✓ zeitwerk 2.8.2 done
66
+ ✓ ruby_llm 1.16.0 done
67
+ ```
68
+
69
+ After completion, each skill is symlinked into `.claude/skills/`:
70
+
71
+ ```
72
+ your-project/.claude/skills/
73
+ ├── rake → ~/.gem/skills/rake/13.4.2/
74
+ ├── ruby_llm → ~/.gem/skills/ruby_llm/1.16.0/
75
+ └── zeitwerk → ~/.gem/skills/zeitwerk/2.8.2/
76
+ ```
77
+
78
+ Claude Code automatically reads `SKILL.md` from each linked directory.
79
+
80
+ ---
81
+
82
+ ### `bundle skill refresh`
83
+
84
+ Re-sync `.claude/skills/` after `bundle update`.
85
+
86
+ ```bash
87
+ bundle skill refresh [OPTIONS]
88
+ ```
89
+
90
+ | Flag | Description |
91
+ |------|-------------|
92
+ | `--force` | Regenerate all skills, even those already at the correct version |
93
+ | `--model MODEL` | LLM model to use |
94
+
95
+ `refresh` skips gems that are already linked at the correct version (shows
96
+ `up to date`), regenerates gems whose version changed, and removes dead symlinks
97
+ for gems no longer in `Gemfile.lock`.
98
+
99
+ **Typical workflow:**
100
+
101
+ ```bash
102
+ bundle update
103
+ bundle skill refresh
104
+ ```
105
+
106
+ ---
107
+
108
+ ### `bundle skill list`
109
+
110
+ Show all skills currently linked in this project.
111
+
112
+ ```bash
113
+ bundle skill list
114
+ ```
115
+
116
+ **Example output:**
117
+
118
+ ```
119
+ Skills linked in .claude/skills/ (3 ok):
120
+
121
+ [ok ] rake 13.4.2
122
+ [ok ] ruby_llm 1.16.0
123
+ [ok ] zeitwerk 2.8.2
124
+ ```
125
+
126
+ A `BROKEN` status means the symlink target no longer exists in the cache —
127
+ run `bundle skill install` to regenerate.
128
+
129
+ ---
130
+
131
+ ## Typical project workflow
132
+
133
+ ```bash
134
+ # First time setup
135
+ bundle install
136
+ bundle skill install
137
+
138
+ # After bundle update
139
+ bundle update
140
+ bundle skill refresh
141
+
142
+ # Check what's linked
143
+ bundle skill list
144
+
145
+ # Force full regeneration (e.g. after model upgrade)
146
+ bundle skill install --force --model claude-opus-4-8
147
+ ```
@@ -0,0 +1,135 @@
1
+ # gem skill
2
+
3
+ The `gem skill` command manages the global skill cache at `~/.gem/skills`.
4
+ It works with any installed gem regardless of project context.
5
+
6
+ ## Subcommands
7
+
8
+ ### `gem skill install`
9
+
10
+ Generate and cache a `SKILL.md` for one or more gems.
11
+
12
+ ```bash
13
+ gem skill install GEM_NAME [GEM_NAME ...]
14
+ ```
15
+
16
+ **Options:**
17
+
18
+ | Flag | Description |
19
+ |------|-------------|
20
+ | `--force`, `-f` | Regenerate even if a skill is already cached |
21
+ | `--model MODEL`, `-m MODEL` | LLM model to use (overrides `GEMSKILL_MODEL`) |
22
+ | `--version`, `-v` | Print the installed gem-skill version and exit |
23
+
24
+ **Examples:**
25
+
26
+ ```bash
27
+ # Single gem (version auto-detected from installed gems)
28
+ gem skill install debug_me
29
+
30
+ # Multiple gems concurrently
31
+ gem skill install faraday zeitwerk dry-validation
32
+
33
+ # Force regeneration with a specific model
34
+ gem skill install rails --force --model claude-opus-4-8
35
+ ```
36
+
37
+ If a gem is not installed locally, gem-skill will install it automatically
38
+ before generating the skill.
39
+
40
+ ---
41
+
42
+ ### `gem skill --version`
43
+
44
+ Print the installed gem-skill version and exit.
45
+
46
+ ```bash
47
+ gem skill --version
48
+ # 0.1.3
49
+ gem skill -v
50
+ # 0.1.3
51
+ ```
52
+
53
+ All gems are processed concurrently — you'll see a live spinner per gem:
54
+
55
+ ```
56
+ ⠋ Generating skills (claude-sonnet-4-6)
57
+ ✓ debug_me 1.1.0 done
58
+ ✓ faraday 2.12.0 done
59
+ ⠋ zeitwerk 2.8.2
60
+ ```
61
+
62
+ ---
63
+
64
+ ### `gem skill setup`
65
+
66
+ Register gem-skill as a Bundler plugin (run once after `gem install gem-skill`).
67
+
68
+ ```bash
69
+ gem skill setup
70
+ ```
71
+
72
+ This enables `bundle skill` in any project on the machine. See
73
+ [Installation](../installation.md) for details.
74
+
75
+ ---
76
+
77
+ ### `gem skill list`
78
+
79
+ Show all skills currently in the global cache.
80
+
81
+ ```bash
82
+ gem skill list
83
+ ```
84
+
85
+ **Example output:**
86
+
87
+ ```
88
+ Cached skills in /Users/you/.gem/skills:
89
+
90
+ debug_me 1.1.0
91
+ faraday 2.12.0, 2.14.3
92
+ zeitwerk 2.8.2
93
+
94
+ 3 gem(s), 4 version(s) total.
95
+ ```
96
+
97
+ ---
98
+
99
+ ### `gem skill purge`
100
+
101
+ Remove a cached skill version.
102
+
103
+ ```bash
104
+ # Remove a specific version
105
+ gem skill purge GEM_NAME VERSION
106
+
107
+ # Remove all cached versions of a gem
108
+ gem skill purge GEM_NAME --all
109
+ ```
110
+
111
+ **Examples:**
112
+
113
+ ```bash
114
+ gem skill purge faraday 2.12.0
115
+ gem skill purge rails --all
116
+ ```
117
+
118
+ ---
119
+
120
+ ## `gem install --with-skill`
121
+
122
+ Generate skills automatically as you install gems:
123
+
124
+ ```bash
125
+ gem install faraday zeitwerk --with-skill
126
+ ```
127
+
128
+ All gems install normally first. Skills are then generated concurrently after
129
+ all installs complete — same spinner UI as `gem skill install`.
130
+
131
+ This works for any `gem install` command, including version-pinned installs:
132
+
133
+ ```bash
134
+ gem install rails --version "~> 7.1" --with-skill
135
+ ```
@@ -0,0 +1,75 @@
1
+ # Configuration
2
+
3
+ ## LLM provider API keys
4
+
5
+ gem-skill uses [RubyLLM](https://github.com/crmne/ruby_llm) to generate skills.
6
+ Set at least one provider API key before running any `install` command:
7
+
8
+ ```bash
9
+ export ANTHROPIC_API_KEY="sk-ant-..." # Claude models
10
+ export OPENAI_API_KEY="sk-..." # GPT models
11
+ export GEMINI_API_KEY="..." # Gemini models
12
+ ```
13
+
14
+ Other supported providers:
15
+
16
+ | Environment variable | Provider |
17
+ |------------------------|--------------|
18
+ | `ANTHROPIC_API_KEY` | Anthropic |
19
+ | `OPENAI_API_KEY` | OpenAI |
20
+ | `GEMINI_API_KEY` | Google Gemini|
21
+ | `MISTRAL_API_KEY` | Mistral |
22
+ | `DEEPSEEK_API_KEY` | DeepSeek |
23
+ | `OPENROUTER_API_KEY` | OpenRouter |
24
+ | `XAI_API_KEY` | xAI (Grok) |
25
+
26
+ ## gem-skill environment variables
27
+
28
+ ### `GEMSKILL_DIR`
29
+
30
+ Controls where generated skills are cached.
31
+
32
+ | | |
33
+ |---|---|
34
+ | **Default** | `~/.gem/skills` |
35
+ | **Example** | `export GEMSKILL_DIR="/Volumes/shared/gem-skills"` |
36
+
37
+ Useful for sharing a skill cache across machines via a network drive, or for
38
+ keeping skills in a non-standard location.
39
+
40
+ ### `GEMSKILL_MODEL`
41
+
42
+ Controls which LLM model is used when generating skills.
43
+
44
+ | | |
45
+ |---|---|
46
+ | **Default** | `gpt-5.5` |
47
+ | **Example** | `export GEMSKILL_MODEL="claude-opus-4-8"` |
48
+
49
+ The `--model` flag on any command overrides `GEMSKILL_MODEL` for that single
50
+ invocation only.
51
+
52
+ ## Recommended shell configuration
53
+
54
+ Add to your `~/.zshrc` or `~/.bashrc`:
55
+
56
+ ```bash
57
+ export ANTHROPIC_API_KEY="sk-ant-..."
58
+ export GEMSKILL_MODEL="claude-sonnet-4-6" # or whichever model you prefer
59
+ ```
60
+
61
+ ## Model selection guidance
62
+
63
+ | Model | Best for |
64
+ |-------|----------|
65
+ | Claude Opus 4.8 | Highest quality skills; comprehensive coverage |
66
+ | Claude Sonnet 4.6 | Good balance of quality and speed |
67
+ | Claude Haiku 4.5 | Fast, cheap; good for simple gems |
68
+ | GPT-5.5 | Default; strong general-purpose coverage |
69
+
70
+ Pass `--model MODEL` to any install command to override for one run:
71
+
72
+ ```bash
73
+ gem skill install rails --model claude-opus-4-8
74
+ bundle skill install --model claude-haiku-4-5
75
+ ```
@@ -0,0 +1,160 @@
1
+ # How It Works
2
+
3
+ gem-skill is built as a pipeline of independent modules. Each has a single
4
+ responsibility and can be used or tested in isolation.
5
+
6
+ ## Pipeline overview
7
+
8
+ ```
9
+ Gemfile.lock / gem name
10
+ ↓
11
+ Lockfile parse direct deps + gemspec deps
12
+ ↓
13
+ Fetcher collect documentation from multiple sources
14
+ ↓
15
+ Generator call LLM, produce SKILL.md content
16
+ ↓
17
+ Cache write to ~/.gem/skills/<gem>/<version>/
18
+ ↓
19
+ Linker symlink .claude/skills/<gem> → cache dir
20
+ ```
21
+
22
+ `Runner.install_skill` is the glue that drives steps 2–5 for a single gem.
23
+ The CLI commands (`gem skill`, `bundle skill`) fan it out concurrently across
24
+ multiple gems using async fibers.
25
+
26
+ ---
27
+
28
+ ## Modules
29
+
30
+ ### Lockfile
31
+
32
+ `lib/gem/skill/lockfile.rb`
33
+
34
+ Parses `Gemfile.lock` to produce a `{ gem_name => version }` hash of the gems
35
+ to process. Reads from two sections:
36
+
37
+ - **`DEPENDENCIES`** — direct deps listed in `Gemfile`
38
+ - **`PATH` → `specs:`** — runtime deps from any `gemspec` referenced by `gemspec` in `Gemfile`
39
+
40
+ Versions are resolved from the `GEM → specs:` section, which contains the full
41
+ lockfile-resolved version for every gem.
42
+
43
+ ### Fetcher
44
+
45
+ `lib/gem/skill/fetcher.rb`
46
+
47
+ Collects documentation from up to three sources, tried in priority order:
48
+
49
+ 1. **Local gem install** — reads `README` and `CHANGELOG` from the gem's install directory via `Gem::Specification`
50
+ 2. **RubyGems API** — fetches summary, runtime dependencies, source URI
51
+ 3. **GitHub raw README** — fetched when the gem is not installed locally; tries `main` then `master` branches, and four common README filename variants
52
+
53
+ Content is truncated at 60,000 characters per source to avoid blowing the LLM
54
+ context window.
55
+
56
+ ### Generator
57
+
58
+ `lib/gem/skill/generator.rb`
59
+
60
+ Calls the LLM via `ruby_llm`. Constructs a detailed prompt instructing the
61
+ model to produce a structured `SKILL.md` covering:
62
+
63
+ - Overview, Installation, Core API, Common Patterns, Gotchas, Configuration, Testing
64
+
65
+ Supports both streaming (live output) and non-streaming modes. Strips any
66
+ markdown code fence wrapper the model adds despite being told not to.
67
+
68
+ The model is configurable via `GEMSKILL_MODEL` or `--model`.
69
+
70
+ ### Cache
71
+
72
+ `lib/gem/skill/cache.rb`
73
+
74
+ Manages the global skill cache. Structure:
75
+
76
+ ```
77
+ ~/.gem/skills/ (GEMSKILL_DIR)
78
+ └── <gem_name>/
79
+ └── <version>/
80
+ ├── SKILL.md
81
+ └── metadata.json (gem, version, model, generated_at, sources)
82
+ ```
83
+
84
+ `Cache::ROOT` is set once at load time from `GEMSKILL_DIR` (default: `~/.gem/skills`).
85
+
86
+ ### Linker
87
+
88
+ `lib/gem/skill/linker.rb`
89
+
90
+ Creates and manages directory symlinks in `.claude/skills/` inside a project:
91
+
92
+ ```
93
+ .claude/skills/<gem_name> → ~/.gem/skills/<gem_name>/<version>/
94
+ ```
95
+
96
+ Symlinks point to the **version directory**, not directly to `SKILL.md`.
97
+ Claude Code discovers `SKILL.md` by reading inside the linked directory.
98
+
99
+ `Linker.prune_dead_links` removes any symlink whose target no longer exists
100
+ in the cache (e.g. after `gem skill purge`).
101
+
102
+ ### Runner
103
+
104
+ `lib/gem/skill/runner.rb`
105
+
106
+ Shared core used by both CLI commands. Drives one gem through the
107
+ cache-check → generate → link sequence:
108
+
109
+ ```ruby
110
+ Runner.install_skill(gem_name, version, spinner, force:, model:)
111
+ # Returns nil on success, error message string on failure
112
+ ```
113
+
114
+ Returns the error message rather than raising, so the caller (the concurrent
115
+ fiber) can record it without killing other in-flight fibers.
116
+
117
+ ---
118
+
119
+ ## Concurrency
120
+
121
+ Both CLI commands use the `async` gem with `Async::Barrier`:
122
+
123
+ ```ruby
124
+ Async do
125
+ barrier = Async::Barrier.new
126
+ gems.each do |gem_name, version|
127
+ barrier.async { Runner.install_skill(...) }
128
+ end
129
+ barrier.wait
130
+ ensure
131
+ barrier.stop
132
+ end
133
+ ```
134
+
135
+ Each gem gets its own fiber. Fibers yield to the event loop during network I/O
136
+ (HTTP fetches, LLM API calls), so all gems make progress concurrently on a
137
+ single thread. This is more memory-efficient than one thread per gem.
138
+
139
+ ---
140
+
141
+ ## Plugin architecture
142
+
143
+ gem-skill registers itself in two ways:
144
+
145
+ ### RubyGems plugin (`lib/rubygems_plugin.rb`)
146
+
147
+ Auto-loaded by RubyGems on every `gem` command via the `rubygems_plugin`
148
+ naming convention. Prepends `Gem::Skill::InstallSkillOption` onto
149
+ `Gem::Commands::InstallCommand` to add the `--with-skill` flag.
150
+
151
+ After all gem installs complete, `Gem.post_install` collects gem names/versions
152
+ into a pending list, and `at_exit` fires `generate_pending_skills` to process
153
+ them concurrently.
154
+
155
+ ### Bundler plugin (`plugins.rb`)
156
+
157
+ Registered via `bundle plugin install gem-skill` (or `gem skill setup`).
158
+ Bundler's plugin API loads `plugins.rb` and discovers the
159
+ `Gem::Skill::BundlerPlugin` class, which routes `bundle skill SUBCOMMAND` to
160
+ `Gem::Skill::BundlerCommand`.
data/docs/index.md ADDED
@@ -0,0 +1,69 @@
1
+ <p align="center">
2
+ <table style="width:38%;margin:0 auto;" border="0" cellpadding="8">
3
+ <tr>
4
+ <td width="40%"><img src="assets/images/gem-skill.jpg" alt="gem-skill logo" style="width:100%;display:block;"></td>
5
+ <td width="60%">
6
+ Generate Claude Code skill files from Ruby gem
7
+ documentation and caches them globally so every project that uses a gem
8
+ can share the same pre-built knowledge.<br><br>
9
+ <strong><a href="https://madbomber.github.io/gem-skill">Full documentation →</a></strong>
10
+ </td>
11
+ </tr>
12
+ </table>
13
+ </p>
14
+
15
+ ## The problem it solves
16
+
17
+ Every time Claude Code encounters a gem it hasn't seen in the current context,
18
+ it re-reads the README, scans examples, and figures out the API. That costs
19
+ tokens and time — and the result evaporates when the conversation ends.
20
+
21
+ `gem-skill` runs that pipeline once, offline, and stores the output as a
22
+ `SKILL.md` in `~/.gem/skills`. Projects symlink to the cached version, so
23
+ Claude has accurate, version-specific knowledge about each gem without
24
+ repeating the ingestion work.
25
+
26
+ ## Quick start
27
+
28
+ ```bash
29
+ # 1. Install
30
+ gem install gem-skill
31
+
32
+ # 2. Register the Bundler plugin (once per machine)
33
+ gem skill setup
34
+
35
+ # 3. Generate a skill for any installed gem
36
+ gem skill install debug_me
37
+
38
+ # 4. In a project — generate skills for all direct dependencies
39
+ cd your-project
40
+ bundle skill install
41
+ ```
42
+
43
+ ## How it works
44
+
45
+ ```
46
+ gem README / changelog / RubyGems API
47
+ ↓
48
+ Fetcher collects docs
49
+ ↓
50
+ Generator calls LLM (ruby_llm)
51
+ ↓
52
+ SKILL.md cached at ~/.gem/skills/<gem>/<version>/
53
+ ↓
54
+ Linker creates .claude/skills/<gem> → cache dir
55
+ ↓
56
+ Claude Code reads SKILL.md automatically
57
+ ```
58
+
59
+ All concurrent work is handled by async fibers — multiple gems are processed
60
+ simultaneously with live TTY spinner progress.
61
+
62
+ ## Key features
63
+
64
+ - **Global cache** — generate once, use everywhere; skills are version-specific
65
+ - **Gemfile.lock awareness** — `bundle skill install` installs skills for every direct dependency including gemspec runtime deps
66
+ - **Concurrent** — all LLM calls run concurrently via async fibers
67
+ - **Two interfaces** — `gem skill` for global cache management, `bundle skill` for project-aware linking
68
+ - **Auto-install** — `gem install --with-skill` generates skills during normal gem installation
69
+ - **Configurable** — `GEMSKILL_DIR` and `GEMSKILL_MODEL` environment variables
@@ -0,0 +1,62 @@
1
+ # Installation
2
+
3
+ ## Requirements
4
+
5
+ - Ruby >= 3.2.0
6
+ - At least one LLM provider API key (see [Configuration](configuration.md))
7
+
8
+ ## Install the gem
9
+
10
+ ```bash
11
+ gem install gem-skill
12
+ ```
13
+
14
+ This makes the `gem skill` subcommand available immediately.
15
+
16
+ ## Register the Bundler plugin
17
+
18
+ To enable `bundle skill` in your projects, run once after installation:
19
+
20
+ ```bash
21
+ gem skill setup
22
+ ```
23
+
24
+ This registers gem-skill as a Bundler plugin globally. You only need to do this
25
+ once per machine.
26
+
27
+ !!! tip "Alternative: per-project plugin"
28
+ You can also add the plugin to a specific project's `Gemfile`:
29
+ ```ruby
30
+ plugin "gem-skill"
31
+ ```
32
+ This installs the plugin for that project only.
33
+
34
+ ## Verify installation
35
+
36
+ ```bash
37
+ # Check gem skill is available
38
+ gem skill
39
+
40
+ # Check bundle skill is available (after gem skill setup)
41
+ bundle skill
42
+ ```
43
+
44
+ ## Upgrading
45
+
46
+ ```bash
47
+ gem update gem-skill
48
+ gem skill setup # re-register the Bundler plugin with the new version
49
+ ```
50
+
51
+ ## Development installation
52
+
53
+ To run from source without building and releasing a gem:
54
+
55
+ ```bash
56
+ git clone https://github.com/madbomber/gem-skill
57
+ cd gem-skill
58
+ bundle install
59
+ bin/dev_install # points both Bundler plugin indexes at the source tree
60
+ ```
61
+
62
+ `bin/dev_install --reset` restores the indexes to the last released gem.
@@ -0,0 +1,78 @@
1
+ # Skill Files
2
+
3
+ A `SKILL.md` is a structured Markdown document that gives Claude Code deep,
4
+ practical knowledge about a Ruby gem. Claude reads it automatically when it is
5
+ present in `.claude/skills/`.
6
+
7
+ ## Format
8
+
9
+ Every generated skill starts with a top-level heading identifying the gem and
10
+ version, then covers seven sections:
11
+
12
+ ```markdown
13
+ # faraday v2.14.3
14
+
15
+ ## Overview
16
+ What the gem does and when to reach for it.
17
+
18
+ ## Installation
19
+ Exact Gemfile/gemspec lines and any required post-install steps.
20
+
21
+ ## Core API
22
+ Key classes, methods, and options with real method signatures and return values.
23
+
24
+ ## Common Patterns
25
+ The 3–5 most frequent real-world usage patterns with working code examples.
26
+
27
+ ## Gotchas & Edge Cases
28
+ Surprising defaults, version-specific behavior, thread safety, encoding issues.
29
+
30
+ ## Configuration
31
+ Initializer patterns, environment variables, defaults worth knowing.
32
+
33
+ ## Testing
34
+ How to test code that uses this gem: mocks, fakes, fixtures, VCR patterns.
35
+ ```
36
+
37
+ ## What Claude does with it
38
+
39
+ When Claude Code opens a project containing `.claude/skills/`, it reads every
40
+ `SKILL.md` it finds. This means:
41
+
42
+ - Claude knows the correct API for the exact version you're using
43
+ - No token cost re-deriving usage from READMEs mid-conversation
44
+ - The knowledge persists across conversation turns
45
+ - Multiple gems can be in scope simultaneously
46
+
47
+ ## Sources used to generate
48
+
49
+ The LLM is given up to three sources per gem (in priority order):
50
+
51
+ 1. **Local README + CHANGELOG** — from the gem's install directory
52
+ 2. **RubyGems API** — summary, dependencies, source URI
53
+ 3. **GitHub raw README** — fetched when not installed locally
54
+
55
+ Content is synthesized, not copied verbatim. The model is instructed to write
56
+ as a knowledgeable colleague, not a marketing document.
57
+
58
+ ## Quality and regeneration
59
+
60
+ Skill quality depends on the documentation available for the gem and the model
61
+ used. For gems with poor upstream documentation, results will reflect that.
62
+
63
+ To improve a skill:
64
+
65
+ ```bash
66
+ # Use a more capable model
67
+ gem skill install my_gem --force --model claude-opus-4-8
68
+
69
+ # Or set it as the default
70
+ export GEMSKILL_MODEL="claude-opus-4-8"
71
+ gem skill install my_gem --force
72
+ ```
73
+
74
+ ## Version specificity
75
+
76
+ Skills are cached per version. `faraday 2.12.0` and `faraday 2.14.3` each get
77
+ their own `SKILL.md`. Symlinks in `.claude/skills/` point to the version
78
+ matching your `Gemfile.lock`, so Claude always has the right version context.
@@ -17,6 +17,11 @@ module Gem::Skill
17
17
  opts, rest = parse_options(args)
18
18
  subcmd = rest.shift
19
19
 
20
+ if opts[:version]
21
+ puts Gem::Skill::VERSION
22
+ return
23
+ end
24
+
20
25
  case subcmd
21
26
  when "install" then install(opts)
22
27
  when "refresh" then refresh(opts)
@@ -146,6 +151,7 @@ module Gem::Skill
146
151
  args.each do |arg|
147
152
  case arg
148
153
  when "--force" then opts[:force] = true
154
+ when "--version", "-v" then opts[:version] = true
149
155
  when /\A--model(?:=(.+))?\z/
150
156
  opts[:model] = $1 || args[args.index(arg) + 1]
151
157
  else
@@ -170,6 +176,7 @@ module Gem::Skill
170
176
  Options:
171
177
  --force Regenerate even if already cached
172
178
  --model MODEL LLM model to use (default: #{Generator::DEFAULT_MODEL})
179
+ --version, -v Print gem-skill version and exit
173
180
  USAGE
174
181
  end
175
182
  private_class_method :usage
@@ -18,6 +18,7 @@ class Gem::Commands::SkillCommand < Gem::Command
18
18
  add_option("-m", "--model MODEL", "LLM model to use (default: #{Gem::Skill::Generator::DEFAULT_MODEL})") do |model, o|
19
19
  o[:model] = model
20
20
  end
21
+ add_option("-v", "--version", "Print gem-skill version and exit") { |_, o| o[:version] = true }
21
22
  end
22
23
 
23
24
  def arguments
@@ -44,6 +45,10 @@ class Gem::Commands::SkillCommand < Gem::Command
44
45
  end
45
46
 
46
47
  def execute
48
+ if options[:version]
49
+ say Gem::Skill::VERSION
50
+ return
51
+ end
47
52
  Gem::Skill.configure_llm!
48
53
  subcmd = options[:args].shift
49
54
  case subcmd
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gem::Skill
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
5
5
  end
data/mkdocs.yml ADDED
@@ -0,0 +1,115 @@
1
+ site_name: gem-skill
2
+ site_description: Generate and manage Claude Code AI skills from Ruby gem documentation
3
+ site_author: Dewayne VanHoozer
4
+ site_url: https://madbomber.github.io/gem-skill
5
+ copyright: Copyright &copy; 2026 Dewayne VanHoozer
6
+
7
+ repo_name: madbomber/gem-skill
8
+ repo_url: https://github.com/madbomber/gem-skill
9
+ edit_uri: edit/main/docs/
10
+
11
+ theme:
12
+ name: material
13
+
14
+ palette:
15
+ - scheme: default
16
+ primary: deep purple
17
+ accent: purple
18
+ toggle:
19
+ icon: material/brightness-7
20
+ name: Switch to dark mode
21
+ - scheme: slate
22
+ primary: deep purple
23
+ accent: purple
24
+ toggle:
25
+ icon: material/brightness-4
26
+ name: Switch to light mode
27
+
28
+ font:
29
+ text: Roboto
30
+ code: Roboto Mono
31
+
32
+ features:
33
+ - navigation.instant
34
+ - navigation.tracking
35
+ - navigation.tabs
36
+ - navigation.tabs.sticky
37
+ - navigation.sections
38
+ - navigation.path
39
+ - navigation.indexes
40
+ - navigation.top
41
+ - toc.follow
42
+ - search.suggest
43
+ - search.highlight
44
+ - search.share
45
+ - header.autohide
46
+ - content.code.copy
47
+ - content.code.annotate
48
+ - content.tabs.link
49
+ - content.tooltips
50
+ - content.action.edit
51
+ - content.action.view
52
+
53
+ plugins:
54
+ - search:
55
+ separator: '[\s\-,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])'
56
+
57
+ markdown_extensions:
58
+ - abbr
59
+ - admonition
60
+ - attr_list
61
+ - def_list
62
+ - footnotes
63
+ - md_in_html
64
+ - toc:
65
+ permalink: true
66
+ title: On this page
67
+ - pymdownx.betterem:
68
+ smart_enable: all
69
+ - pymdownx.caret
70
+ - pymdownx.details
71
+ - pymdownx.emoji:
72
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
73
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
74
+ - pymdownx.highlight:
75
+ anchor_linenums: true
76
+ line_spans: __span
77
+ pygments_lang_class: true
78
+ - pymdownx.inlinehilite
79
+ - pymdownx.keys
80
+ - pymdownx.magiclink:
81
+ repo_url_shorthand: true
82
+ user: madbomber
83
+ repo: gem-skill
84
+ - pymdownx.mark
85
+ - pymdownx.smartsymbols
86
+ - pymdownx.superfences:
87
+ custom_fences:
88
+ - name: mermaid
89
+ class: mermaid
90
+ format: !!python/name:pymdownx.superfences.fence_code_format
91
+ - pymdownx.tabbed:
92
+ alternate_style: true
93
+ - pymdownx.tasklist:
94
+ custom_checkbox: true
95
+ - pymdownx.tilde
96
+
97
+ extra:
98
+ social:
99
+ - icon: fontawesome/brands/github
100
+ link: https://github.com/madbomber/gem-skill
101
+ name: gem-skill on GitHub
102
+ - icon: fontawesome/solid/gem
103
+ link: https://rubygems.org/gems/gem-skill
104
+ name: gem-skill on RubyGems
105
+
106
+ nav:
107
+ - Home: index.md
108
+ - Installation: installation.md
109
+ - Configuration: configuration.md
110
+ - Commands:
111
+ - gem skill: commands/gem-skill.md
112
+ - bundle skill: commands/bundle-skill.md
113
+ - How It Works: how-it-works.md
114
+ - Cache: cache.md
115
+ - Skill Files: skill-files.md
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem-skill
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dewayne VanHoozer
@@ -63,10 +63,20 @@ extensions: []
63
63
  extra_rdoc_files: []
64
64
  files:
65
65
  - ".envrc"
66
+ - ".github/workflows/deploy-github-pages.yml"
66
67
  - CHANGELOG.md
67
68
  - LICENSE.txt
68
69
  - README.md
69
70
  - Rakefile
71
+ - docs/assets/images/gem-skill.jpg
72
+ - docs/cache.md
73
+ - docs/commands/bundle-skill.md
74
+ - docs/commands/gem-skill.md
75
+ - docs/configuration.md
76
+ - docs/how-it-works.md
77
+ - docs/index.md
78
+ - docs/installation.md
79
+ - docs/skill-files.md
70
80
  - lib/gem/skill.rb
71
81
  - lib/gem/skill/cache.rb
72
82
  - lib/gem/skill/cli/bundle_command.rb
@@ -78,6 +88,7 @@ files:
78
88
  - lib/gem/skill/runner.rb
79
89
  - lib/gem/skill/version.rb
80
90
  - lib/rubygems_plugin.rb
91
+ - mkdocs.yml
81
92
  - plugins.rb
82
93
  - scripts/e2e_test
83
94
  - sig/gem/skill.rbs
@@ -87,7 +98,7 @@ licenses:
87
98
  metadata:
88
99
  homepage_uri: https://github.com/madbomber/gem-skill
89
100
  source_code_uri: https://github.com/madbomber/gem-skill
90
- changelog_uri: https://github.com/madbomber/gem-skill/blob/master/CHANGELOG.md
101
+ changelog_uri: https://github.com/madbomber/gem-skill/blob/main/CHANGELOG.md
91
102
  post_install_message: |
92
103
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
93
104
  gem-skill installed!