gem-skill 0.1.2 → 0.2.0
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 +4 -4
- data/.github/workflows/deploy-github-pages.yml +52 -0
- data/CHANGELOG.md +55 -0
- data/README.md +71 -13
- data/docs/assets/images/gem-skill.jpg +0 -0
- data/docs/cache.md +185 -0
- data/docs/commands/bundle-skill.md +154 -0
- data/docs/commands/gem-skill.md +212 -0
- data/docs/configuration.md +112 -0
- data/docs/how-it-works.md +209 -0
- data/docs/index.md +73 -0
- data/docs/installation.md +62 -0
- data/docs/skill-files.md +141 -0
- data/lib/gem/skill/cache.rb +24 -0
- data/lib/gem/skill/cli/bundle_command.rb +53 -18
- data/lib/gem/skill/cli/gem_command.rb +163 -8
- data/lib/gem/skill/fetcher.rb +52 -0
- data/lib/gem/skill/frontmatter.rb +64 -0
- data/lib/gem/skill/generator.rb +1 -0
- data/lib/gem/skill/linker.rb +17 -3
- data/lib/gem/skill/runner.rb +69 -9
- data/lib/gem/skill/verifier.rb +136 -0
- data/lib/gem/skill/version.rb +1 -1
- data/lib/gem/skill.rb +12 -0
- data/mkdocs.yml +115 -0
- data/ruby-gem-skills/SKILL.md +53 -0
- metadata +16 -2
|
@@ -0,0 +1,212 @@
|
|
|
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
|
+
| `--verify` | After generating, verify the skill's code against the gem's actual source and fix mismatches |
|
|
22
|
+
| `--model MODEL`, `-m MODEL` | LLM model to use (overrides `GEMSKILL_MODEL`) |
|
|
23
|
+
| `--version`, `-v` | Print the installed gem-skill version and exit |
|
|
24
|
+
|
|
25
|
+
**Examples:**
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Single gem (version auto-detected from installed gems)
|
|
29
|
+
gem skill install debug_me
|
|
30
|
+
|
|
31
|
+
# Multiple gems concurrently
|
|
32
|
+
gem skill install faraday zeitwerk dry-validation
|
|
33
|
+
|
|
34
|
+
# Force regeneration with a specific model
|
|
35
|
+
gem skill install rails --force --model claude-opus-4-8
|
|
36
|
+
|
|
37
|
+
# Generate, then verify the result against the gem's source code
|
|
38
|
+
gem skill install tty-spinner --verify
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If a gem is not installed locally, gem-skill will install it automatically
|
|
42
|
+
before generating the skill.
|
|
43
|
+
|
|
44
|
+
### Verifying against source (`--verify`)
|
|
45
|
+
|
|
46
|
+
The generation pass synthesizes a skill from a gem's README, changelog, and
|
|
47
|
+
examples. That prose is sometimes stale or wrong about exact method signatures,
|
|
48
|
+
default argument values, and behavior. `--verify` adds a second pass that checks
|
|
49
|
+
the generated skill against the gem's **actual installed source code** (the only
|
|
50
|
+
source of truth) and rewrites anything the source contradicts.
|
|
51
|
+
|
|
52
|
+
Verification requires the gem to be installed locally (it reads `lib/**/*.rb`).
|
|
53
|
+
If no source is available, the skill is left untouched.
|
|
54
|
+
|
|
55
|
+
**Exit status** (so CI can detect README/source drift):
|
|
56
|
+
|
|
57
|
+
| Code | Meaning |
|
|
58
|
+
|------|---------|
|
|
59
|
+
| `0` | Success — skill was clean, or `--verify` not used |
|
|
60
|
+
| `1` | Error |
|
|
61
|
+
| `2` | `--verify` found and corrected problems |
|
|
62
|
+
|
|
63
|
+
Either way, `metadata.json` gains a `verification` block recording that the gem's
|
|
64
|
+
actual source was consulted, which files were examined, and — when fixes were
|
|
65
|
+
applied — an array of structured, issue-ready corrections (affected symbol,
|
|
66
|
+
source location, what the skill said vs. the truth, and the proving source
|
|
67
|
+
snippet). See [Cache layout](cache.md#metadatajson) for the full schema.
|
|
68
|
+
|
|
69
|
+
A verified skill is flagged with a green checkmark in
|
|
70
|
+
[`gem skill list`](#gem-skill-list).
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
### `gem skill verify`
|
|
75
|
+
|
|
76
|
+
Verify an **already-cached** skill against the gem's source, in place, without
|
|
77
|
+
regenerating it.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
gem skill verify GEM_NAME [GEM_NAME ...]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This runs the same source-truth check as `--verify`, but never generates: the
|
|
84
|
+
gem must be installed (verification reads its source) and the skill must already
|
|
85
|
+
be cached. It errors if either is missing rather than generating a new skill.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Verify the cached tty-spinner skill against its installed source
|
|
89
|
+
gem skill verify tty-spinner
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Exit status matches `--verify`: `0` clean, `1` error, `2` when corrections were
|
|
93
|
+
applied. Verified versions are flagged with a green checkmark in
|
|
94
|
+
[`gem skill list`](#gem-skill-list).
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### `gem skill --version`
|
|
99
|
+
|
|
100
|
+
Print the installed gem-skill version and exit.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
gem skill --version
|
|
104
|
+
# 0.1.3
|
|
105
|
+
gem skill -v
|
|
106
|
+
# 0.1.3
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
All gems are processed concurrently — you'll see a live spinner per gem:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
⠋ Generating skills (claude-sonnet-4-6)
|
|
113
|
+
✓ debug_me 1.1.0 done
|
|
114
|
+
✓ faraday 2.12.0 done
|
|
115
|
+
⠋ zeitwerk 2.8.2
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
### `gem skill setup`
|
|
121
|
+
|
|
122
|
+
Run once after `gem install gem-skill`.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
gem skill setup
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
It does two things:
|
|
129
|
+
|
|
130
|
+
1. **Registers gem-skill as a Bundler plugin** so `bundle skill` works in any
|
|
131
|
+
project on the machine.
|
|
132
|
+
2. **Installs the `ruby-gem-skills` router skill** into the default skill root of
|
|
133
|
+
each detected assistant — `~/.claude/skills` (Claude Code), `~/.codex/skills`
|
|
134
|
+
and `~/.agents/skills` (Codex). A root is only written if its assistant home
|
|
135
|
+
(`~/.claude`, `~/.codex`, `~/.agents`) already exists.
|
|
136
|
+
|
|
137
|
+
The router skill matters because cached gem skills live in `~/.gem/skills`, a
|
|
138
|
+
directory assistants don't scan by default. This small always-on skill triggers
|
|
139
|
+
when you work with a Ruby gem and tells the assistant how to find and read that
|
|
140
|
+
gem's cached `SKILL.md` (resolving the version from `Gemfile.lock` or the
|
|
141
|
+
installed gem). Re-run `gem skill setup` after upgrading gem-skill to refresh the
|
|
142
|
+
copy. See [Installation](../installation.md) for details.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### `gem skill list`
|
|
147
|
+
|
|
148
|
+
Show all skills currently in the global cache. A green checkmark (`✓`) appears
|
|
149
|
+
next to any version whose skill has been verified against the gem's source (via
|
|
150
|
+
`--verify` or `gem skill verify`); unverified versions show no mark.
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
gem skill list
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Example output:**
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
Cached skills in /Users/you/.gem/skills:
|
|
160
|
+
|
|
161
|
+
debug_me 1.1.0
|
|
162
|
+
faraday 2.12.0, 2.14.3 ✓
|
|
163
|
+
zeitwerk 2.8.2 ✓
|
|
164
|
+
|
|
165
|
+
3 gem(s), 4 version(s) total.
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Here `faraday 2.14.3` and `zeitwerk 2.8.2` have verified skills, while
|
|
169
|
+
`faraday 2.12.0` and `debug_me 1.1.0` have not been verified. The checkmark is
|
|
170
|
+
shown in green when the output is an interactive terminal, and as a plain `✓`
|
|
171
|
+
when piped or redirected. "Verified" means the skill was checked against the
|
|
172
|
+
gem's actual source — see [`gem skill verify`](#gem-skill-verify).
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### `gem skill purge`
|
|
177
|
+
|
|
178
|
+
Remove a cached skill version.
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Remove a specific version
|
|
182
|
+
gem skill purge GEM_NAME VERSION
|
|
183
|
+
|
|
184
|
+
# Remove all cached versions of a gem
|
|
185
|
+
gem skill purge GEM_NAME --all
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Examples:**
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
gem skill purge faraday 2.12.0
|
|
192
|
+
gem skill purge rails --all
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## `gem install --with-skill`
|
|
198
|
+
|
|
199
|
+
Generate skills automatically as you install gems:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
gem install faraday zeitwerk --with-skill
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
All gems install normally first. Skills are then generated concurrently after
|
|
206
|
+
all installs complete — same spinner UI as `gem skill install`.
|
|
207
|
+
|
|
208
|
+
This works for any `gem install` command, including version-pinned installs:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
gem install rails --version "~> 7.1" --with-skill
|
|
212
|
+
```
|
|
@@ -0,0 +1,112 @@
|
|
|
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_PROJECT_DIR`
|
|
41
|
+
|
|
42
|
+
The project-relative directory where `bundle skill` writes its symlinks into the
|
|
43
|
+
cache. Change it to match whichever assistant you use.
|
|
44
|
+
|
|
45
|
+
| | |
|
|
46
|
+
|---|---|
|
|
47
|
+
| **Default** | `.claude/skills` (Claude Code) |
|
|
48
|
+
| **Example** | `export GEMSKILL_PROJECT_DIR=".agents"` |
|
|
49
|
+
|
|
50
|
+
`SKILL.md` is a shared format, but each assistant looks for skills in its own
|
|
51
|
+
project directory:
|
|
52
|
+
|
|
53
|
+
| Assistant | Suggested `GEMSKILL_PROJECT_DIR` |
|
|
54
|
+
|--------------|----------------------------------|
|
|
55
|
+
| Claude Code | `.claude/skills` (default) |
|
|
56
|
+
| OpenAI Codex | `.agents` or `.codex` |
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Claude Code (default — no need to set anything)
|
|
60
|
+
bundle skill install
|
|
61
|
+
|
|
62
|
+
# OpenAI Codex — link into a Codex project root instead
|
|
63
|
+
export GEMSKILL_PROJECT_DIR=".agents"
|
|
64
|
+
bundle skill install # symlinks now land in .agents/
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
A blank or unset value falls back to the `.claude/skills` default.
|
|
68
|
+
|
|
69
|
+
!!! note "Availability is not activation"
|
|
70
|
+
Setting `GEMSKILL_PROJECT_DIR` controls *where the symlinks are written*. It
|
|
71
|
+
does not change how an assistant decides a skill is active. Claude Code
|
|
72
|
+
activates every `SKILL.md` under `.claude/skills/` automatically; other
|
|
73
|
+
assistants (e.g. Codex) may require the skill to be in the session's
|
|
74
|
+
available-skills list or referenced explicitly. See
|
|
75
|
+
[Using with other assistants](skill-files.md#using-with-other-assistants).
|
|
76
|
+
|
|
77
|
+
### `GEMSKILL_MODEL`
|
|
78
|
+
|
|
79
|
+
Controls which LLM model is used when generating skills.
|
|
80
|
+
|
|
81
|
+
| | |
|
|
82
|
+
|---|---|
|
|
83
|
+
| **Default** | `gpt-5.5` |
|
|
84
|
+
| **Example** | `export GEMSKILL_MODEL="claude-opus-4-8"` |
|
|
85
|
+
|
|
86
|
+
The `--model` flag on any command overrides `GEMSKILL_MODEL` for that single
|
|
87
|
+
invocation only.
|
|
88
|
+
|
|
89
|
+
## Recommended shell configuration
|
|
90
|
+
|
|
91
|
+
Add to your `~/.zshrc` or `~/.bashrc`:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
95
|
+
export GEMSKILL_MODEL="claude-sonnet-4-6" # or whichever model you prefer
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Model selection guidance
|
|
99
|
+
|
|
100
|
+
| Model | Best for |
|
|
101
|
+
|-------|----------|
|
|
102
|
+
| Claude Opus 4.8 | Highest quality skills; comprehensive coverage |
|
|
103
|
+
| Claude Sonnet 4.6 | Good balance of quality and speed |
|
|
104
|
+
| Claude Haiku 4.5 | Fast, cheap; good for simple gems |
|
|
105
|
+
| GPT-5.5 | Default; strong general-purpose coverage |
|
|
106
|
+
|
|
107
|
+
Pass `--model MODEL` to any install command to override for one run:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
gem skill install rails --model claude-opus-4-8
|
|
111
|
+
bundle skill install --model claude-haiku-4-5
|
|
112
|
+
```
|
|
@@ -0,0 +1,209 @@
|
|
|
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
|
+
Verifier (optional, --verify) check the skill's code against the
|
|
20
|
+
gem's actual source; correct mismatches in place
|
|
21
|
+
↓
|
|
22
|
+
Linker symlink .claude/skills/<gem> → cache dir
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`Runner.install_skill` is the glue that drives steps 2–5 for a single gem.
|
|
26
|
+
The CLI commands (`gem skill`, `bundle skill`) fan it out concurrently across
|
|
27
|
+
multiple gems using async fibers.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Modules
|
|
32
|
+
|
|
33
|
+
### Lockfile
|
|
34
|
+
|
|
35
|
+
`lib/gem/skill/lockfile.rb`
|
|
36
|
+
|
|
37
|
+
Parses `Gemfile.lock` to produce a `{ gem_name => version }` hash of the gems
|
|
38
|
+
to process. Reads from two sections:
|
|
39
|
+
|
|
40
|
+
- **`DEPENDENCIES`** — direct deps listed in `Gemfile`
|
|
41
|
+
- **`PATH` → `specs:`** — runtime deps from any `gemspec` referenced by `gemspec` in `Gemfile`
|
|
42
|
+
|
|
43
|
+
Versions are resolved from the `GEM → specs:` section, which contains the full
|
|
44
|
+
lockfile-resolved version for every gem.
|
|
45
|
+
|
|
46
|
+
### Fetcher
|
|
47
|
+
|
|
48
|
+
`lib/gem/skill/fetcher.rb`
|
|
49
|
+
|
|
50
|
+
Collects documentation from up to three sources, tried in priority order:
|
|
51
|
+
|
|
52
|
+
1. **Local gem install** — reads `README` and `CHANGELOG` from the gem's install directory via `Gem::Specification`
|
|
53
|
+
2. **RubyGems API** — fetches summary, runtime dependencies, source URI
|
|
54
|
+
3. **GitHub raw README** — fetched when the gem is not installed locally; tries `main` then `master` branches, and four common README filename variants
|
|
55
|
+
|
|
56
|
+
Content is truncated at 60,000 characters per source to avoid blowing the LLM
|
|
57
|
+
context window.
|
|
58
|
+
|
|
59
|
+
### Generator
|
|
60
|
+
|
|
61
|
+
`lib/gem/skill/generator.rb`
|
|
62
|
+
|
|
63
|
+
Calls the LLM via `ruby_llm`. Constructs a detailed prompt instructing the
|
|
64
|
+
model to produce a structured `SKILL.md` covering:
|
|
65
|
+
|
|
66
|
+
- Overview, Installation, Core API, Common Patterns, Gotchas, Configuration, Testing
|
|
67
|
+
|
|
68
|
+
Supports both streaming (live output) and non-streaming modes. Strips any
|
|
69
|
+
markdown code fence wrapper the model adds despite being told not to.
|
|
70
|
+
|
|
71
|
+
The model is configurable via `GEMSKILL_MODEL` or `--model`.
|
|
72
|
+
|
|
73
|
+
### Cache
|
|
74
|
+
|
|
75
|
+
`lib/gem/skill/cache.rb`
|
|
76
|
+
|
|
77
|
+
Manages the global skill cache. Structure:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
~/.gem/skills/ (GEMSKILL_DIR)
|
|
81
|
+
└── <gem_name>/
|
|
82
|
+
└── <version>/
|
|
83
|
+
├── SKILL.md
|
|
84
|
+
└── metadata.json (gem, version, model, generated_at, sources,
|
|
85
|
+
and after --verify: a "verification" block with
|
|
86
|
+
source provenance + structured changes)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`Cache::ROOT` is set once at load time from `GEMSKILL_DIR` (default: `~/.gem/skills`).
|
|
90
|
+
|
|
91
|
+
`read_metadata` / `write_skill` / `merge_metadata` let the verifier rewrite a
|
|
92
|
+
cached skill and annotate its metadata without clobbering the original
|
|
93
|
+
`generated_at`, `model`, or `sources`.
|
|
94
|
+
|
|
95
|
+
### Verifier
|
|
96
|
+
|
|
97
|
+
`lib/gem/skill/verifier.rb`
|
|
98
|
+
|
|
99
|
+
Optional second pass, enabled by `--verify`. Generation synthesizes prose
|
|
100
|
+
sources (README, changelog, examples) which are frequently stale or wrong about
|
|
101
|
+
exact signatures. The verifier re-checks the generated skill against the gem's
|
|
102
|
+
**actual source code** — the only source of truth — and corrects mismatched
|
|
103
|
+
method signatures, default argument values, visibility, return values, and
|
|
104
|
+
behavioral claims.
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
Verifier.new(gem_name, version, model:).verify(skill_content)
|
|
108
|
+
# => Result(content:, changes:, changed:, verifiable:, source:, model:)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Ground truth comes from `Fetcher#source_code` (the gem's `lib/**/*.rb`), and
|
|
112
|
+
`Fetcher#source_manifest` records which files were examined. Whether the skill
|
|
113
|
+
actually changed is decided by a **deterministic diff** of the content before and
|
|
114
|
+
after — not by trusting the model's self-report — so the exit code is reliable.
|
|
115
|
+
If no installed source is available, `verifiable` is false and the skill is left
|
|
116
|
+
untouched.
|
|
117
|
+
|
|
118
|
+
Each correction in `changes` is a structured, issue-ready Hash
|
|
119
|
+
(`category`, `symbol`, `skill_section`, `source_location`, `was`, `now`,
|
|
120
|
+
`detail`, `source_evidence`) — detailed enough to file a documentation bug
|
|
121
|
+
against the gem. The Runner writes these, plus source provenance, into the
|
|
122
|
+
`verification` block of `metadata.json`.
|
|
123
|
+
|
|
124
|
+
### Linker
|
|
125
|
+
|
|
126
|
+
`lib/gem/skill/linker.rb`
|
|
127
|
+
|
|
128
|
+
Creates and manages directory symlinks in the project's skill directory
|
|
129
|
+
(default `.claude/skills/`, Claude Code's convention):
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
<project_dir>/<gem_name> → ~/.gem/skills/<gem_name>/<version>/
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The directory is `Linker.project_dir`, read from `GEMSKILL_PROJECT_DIR` each call
|
|
136
|
+
(default `.claude/skills`). Codex users set it to `.agents` or `.codex` so
|
|
137
|
+
`bundle skill` links into a Codex root instead. Symlinks point to the **version
|
|
138
|
+
directory**, not directly to `SKILL.md`; the assistant discovers `SKILL.md` by
|
|
139
|
+
reading inside the linked directory.
|
|
140
|
+
|
|
141
|
+
`Linker.prune_dead_links` removes any symlink whose target no longer exists
|
|
142
|
+
in the cache (e.g. after `gem skill purge`).
|
|
143
|
+
|
|
144
|
+
The cache itself is assistant-neutral. `SKILL.md` is a shared format; other
|
|
145
|
+
assistants read it from their own roots. Note that linking only makes a skill
|
|
146
|
+
*available* — some assistants (e.g. Codex) require it to be in the available-skills
|
|
147
|
+
list or referenced explicitly before it's *active*.
|
|
148
|
+
|
|
149
|
+
### Runner
|
|
150
|
+
|
|
151
|
+
`lib/gem/skill/runner.rb`
|
|
152
|
+
|
|
153
|
+
Shared core used by both CLI commands. Drives one gem through the
|
|
154
|
+
cache-check → generate → link sequence:
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
Runner.install_skill(gem_name, version, spinner, force:, model:, verify:)
|
|
158
|
+
# => Runner::Result(error:, verify_fixed:, change_count:)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Captures errors into the result rather than raising, so the caller (the
|
|
162
|
+
concurrent fiber) can record them without killing other in-flight fibers. When
|
|
163
|
+
`verify:` is set, the result's `verify_fixed` lets the CLI aggregate across all
|
|
164
|
+
gems and exit `2` (`EXIT_VERIFY_FIXED`) if any skill was corrected.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Concurrency
|
|
169
|
+
|
|
170
|
+
Both CLI commands use the `async` gem with `Async::Barrier`:
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
Async do
|
|
174
|
+
barrier = Async::Barrier.new
|
|
175
|
+
gems.each do |gem_name, version|
|
|
176
|
+
barrier.async { Runner.install_skill(...) }
|
|
177
|
+
end
|
|
178
|
+
barrier.wait
|
|
179
|
+
ensure
|
|
180
|
+
barrier.stop
|
|
181
|
+
end
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Each gem gets its own fiber. Fibers yield to the event loop during network I/O
|
|
185
|
+
(HTTP fetches, LLM API calls), so all gems make progress concurrently on a
|
|
186
|
+
single thread. This is more memory-efficient than one thread per gem.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Plugin architecture
|
|
191
|
+
|
|
192
|
+
gem-skill registers itself in two ways:
|
|
193
|
+
|
|
194
|
+
### RubyGems plugin (`lib/rubygems_plugin.rb`)
|
|
195
|
+
|
|
196
|
+
Auto-loaded by RubyGems on every `gem` command via the `rubygems_plugin`
|
|
197
|
+
naming convention. Prepends `Gem::Skill::InstallSkillOption` onto
|
|
198
|
+
`Gem::Commands::InstallCommand` to add the `--with-skill` flag.
|
|
199
|
+
|
|
200
|
+
After all gem installs complete, `Gem.post_install` collects gem names/versions
|
|
201
|
+
into a pending list, and `at_exit` fires `generate_pending_skills` to process
|
|
202
|
+
them concurrently.
|
|
203
|
+
|
|
204
|
+
### Bundler plugin (`plugins.rb`)
|
|
205
|
+
|
|
206
|
+
Registered via `bundle plugin install gem-skill` (or `gem skill setup`).
|
|
207
|
+
Bundler's plugin API loads `plugins.rb` and discovers the
|
|
208
|
+
`Gem::Skill::BundlerPlugin` class, which routes `bundle skill SUBCOMMAND` to
|
|
209
|
+
`Gem::Skill::BundlerCommand`.
|
data/docs/index.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
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 <code>SKILL.md</code> files for AI coding assistants
|
|
7
|
+
(Claude Code, OpenAI Codex, and others) from Ruby gem documentation,
|
|
8
|
+
and cache them globally so every project that uses a gem can share the
|
|
9
|
+
same pre-built knowledge.<br><br>
|
|
10
|
+
<strong><a href="https://madbomber.github.io/gem-skill">Full documentation →</a></strong>
|
|
11
|
+
</td>
|
|
12
|
+
</tr>
|
|
13
|
+
</table>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
## The problem it solves
|
|
17
|
+
|
|
18
|
+
Every time an AI coding assistant encounters a gem it hasn't seen in the current
|
|
19
|
+
context, it re-reads the README, scans examples, and figures out the API. That
|
|
20
|
+
costs tokens and time — and the result evaporates when the conversation ends.
|
|
21
|
+
|
|
22
|
+
`gem-skill` runs that pipeline once, offline, and stores the output as a
|
|
23
|
+
`SKILL.md` in `~/.gem/skills`. Projects symlink to the cached version, so your
|
|
24
|
+
assistant has accurate, version-specific knowledge about each gem without
|
|
25
|
+
repeating the ingestion work. `SKILL.md` is a shared format — Claude Code,
|
|
26
|
+
OpenAI Codex, and other assistants all read it.
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# 1. Install
|
|
32
|
+
gem install gem-skill
|
|
33
|
+
|
|
34
|
+
# 2. Register the Bundler plugin (once per machine)
|
|
35
|
+
gem skill setup
|
|
36
|
+
|
|
37
|
+
# 3. Generate a skill for any installed gem
|
|
38
|
+
gem skill install debug_me
|
|
39
|
+
|
|
40
|
+
# 4. In a project — generate skills for all direct dependencies
|
|
41
|
+
cd your-project
|
|
42
|
+
bundle skill install
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## How it works
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
gem README / changelog / RubyGems API
|
|
49
|
+
↓
|
|
50
|
+
Fetcher collects docs
|
|
51
|
+
↓
|
|
52
|
+
Generator calls LLM (ruby_llm)
|
|
53
|
+
↓
|
|
54
|
+
SKILL.md cached at ~/.gem/skills/<gem>/<version>/
|
|
55
|
+
↓
|
|
56
|
+
Linker creates .claude/skills/<gem> → cache dir
|
|
57
|
+
↓
|
|
58
|
+
The assistant reads SKILL.md automatically
|
|
59
|
+
(Claude Code from .claude/skills/; other assistants from their own roots)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
All concurrent work is handled by async fibers — multiple gems are processed
|
|
63
|
+
simultaneously with live TTY spinner progress.
|
|
64
|
+
|
|
65
|
+
## Key features
|
|
66
|
+
|
|
67
|
+
- **Global cache** — generate once, use everywhere; skills are version-specific
|
|
68
|
+
- **Gemfile.lock awareness** — `bundle skill install` installs skills for every direct dependency including gemspec runtime deps
|
|
69
|
+
- **Concurrent** — all LLM calls run concurrently via async fibers
|
|
70
|
+
- **Two interfaces** — `gem skill` for global cache management, `bundle skill` for project-aware linking
|
|
71
|
+
- **Auto-install** — `gem install --with-skill` generates skills during normal gem installation
|
|
72
|
+
- **Configurable** — `GEMSKILL_DIR`, `GEMSKILL_PROJECT_DIR`, and `GEMSKILL_MODEL` environment variables
|
|
73
|
+
- **Multi-assistant** — `SKILL.md` works with Claude Code, OpenAI Codex, and others; `GEMSKILL_PROJECT_DIR` points project links at the right directory
|
|
@@ -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.
|