ruby-skill-bench 1.4.0 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78725cfc6d6bcc768b30cdd3da521d4895b7f24d1bd388e1056818a45ae71714
4
- data.tar.gz: f589debec2945344a06c59443dab4b0a64ee969467cb814d86674e2b706acdf9
3
+ metadata.gz: cb1aca517e3a5d2599b68f7bff39222f556e0bc6bce90490b0f1d5358f6547c2
4
+ data.tar.gz: 7e8dffa808ea6248d8b84b00492066f071c8771cb8fc7bbb25121149270affaa
5
5
  SHA512:
6
- metadata.gz: 6981311a0bd893fb0f0a443cec3934623ae5fab6c1088ea8b720ce55ef0b901b6851bfc06aed29b355dd187cfc0864c24e59bc2959b24e2bd3479bdeb920db03
7
- data.tar.gz: ed4e639a719d6ab023e53f43484d48e591d1289559d8b178705905e480dbc682fe109915a461d8b547a733507f132b113790db6b7c325df5df7c27719c649b52
6
+ metadata.gz: 1d1bf40f9e8bb02757be1bb2fb2fa5a68187d3bbc472852ce34306aaf85782a6b8acdb8b977d1779f03c8a717c9874fe98f09856925f1446575a519c91a5e997
7
+ data.tar.gz: 42b9b9311d45a376e9d3e15a75be1cdf43bbcf234db2180c23cab7085a64b224026b5b2b6097be33118b532f7f6728f32787168cfa1fdd5cc1fd2bd6cd5a3d45
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/igmarin/ruby-skill-bench)
8
8
 
9
- *A high-fidelity evaluation engine for benchmarking AI agent skills across any stack (Rails-first, but extensible).*
9
+ Ruby Skill Bench compares how an AI coding agent completes the same task with and without a skill. It runs both attempts in temporary Git sandboxes, then scores them against criteria you define. You can use it with Ruby projects and other stacks.
10
10
 
11
11
  ## Part of the AI Skill Ecosystem
12
12
 
@@ -27,12 +27,11 @@ See the [Ecosystem Overview](https://github.com/igmarin/agent-mcp-runtime/blob/m
27
27
 
28
28
  ## Features
29
29
 
30
- - **Side-by-Side Evaluation**: Quantify the "ROI of Context" by comparing baseline vs. skill-enhanced agent runs.
31
- - **Isolated Git Sandboxes**: Every run operates in a temporary repo. Clean diffs, zero side-effects, 100% reproducibility.
32
- - **Blind Judging with Dimensions**: LLM judge scores baseline and context independently across 5 canonical dimensions (Correctness, Skill Adherence, Code Quality, Test Coverage, Documentation). Eval authors configure weights and thresholds via `criteria.json`.
33
- - **Sophisticated ReAct Loop**: Employs a robust `Thought → Tool → Observation` loop to handle complex, multi-step engineering tasks.
34
- - **Multi-Provider Ecosystem**: Native support for **OpenAI**, **Anthropic**, **Google Gemini**, **Azure OpenAI**, **Ollama**, **Groq**, **DeepSeek**, **Mistral**, **OpenCode**, **OpenRouter**, **xAI**, and **Amazon Bedrock**.
35
- - **Standardized Intelligence**: Consistent reporting format regardless of the underlying LLM provider.
30
+ - **Compare two runs**: See what changes when an agent receives a skill.
31
+ - **Isolate evaluation work**: Each attempt runs in its own temporary Git sandbox.
32
+ - **Score against your criteria**: Configure dimensions, weights, and pass thresholds in `criteria.json`.
33
+ - **Use your provider**: OpenAI, Anthropic, Google Gemini, Azure OpenAI, Ollama, Groq, DeepSeek, Mistral, OpenCode, OpenRouter, xAI, and Amazon Bedrock are supported.
34
+ - **Get consistent reports**: The output format stays the same across providers.
36
35
 
37
36
  ---
38
37
 
@@ -118,6 +117,8 @@ Configuration is loaded in this order (later sources override earlier ones):
118
117
 
119
118
  ## Getting Started
120
119
 
120
+ Ruby Skill Bench requires Ruby 3.3 or newer. For a guided first run, see the [5-minute first eval guide](docs/first-eval-guide.md).
121
+
121
122
  ### Installation
122
123
 
123
124
  ```bash
@@ -184,7 +185,7 @@ skills/
184
185
 
185
186
  **Example `SKILL.md`:**
186
187
 
187
- ```markdown
188
+ ````markdown
188
189
  # Service Object Skill
189
190
 
190
191
  ## Pattern
@@ -200,7 +201,7 @@ All service objects use the `.call` class method and return a standardized hash:
200
201
  1. Every `.rb` file begins with `# frozen_string_literal: true`
201
202
  2. Every public method has YARD docs (`@param`, `@return`, `@raise`)
202
203
  3. `rescue StandardError` blocks must log backtrace
203
- ```
204
+ ````
204
205
 
205
206
  ---
206
207
 
@@ -1153,7 +1154,7 @@ jobs:
1153
1154
 
1154
1155
  The action installs the gem and runs `skill-bench run --all --evals-dir <evals-dir> --format <format>` (adding `--skill` when set and appending `args` verbatim). The run step's exit code is the gate. For a full copy-paste workflow template, see [`examples/ci/`](examples/ci/).
1155
1156
 
1156
- > The gem's own repository CI (`.github/workflows/ci.yml`) runs the test suite — rubocop, reek, and minitest against Ruby 3.3 and 3.4, on push and pull requests — and is separate from the reusable action above.
1157
+ > The gem's own repository CI (`.github/workflows/ci.yml`) runs RuboCop, Reek, and Minitest on Ruby 3.3, 3.4, and 4.0. This is separate from the reusable action above.
1157
1158
 
1158
1159
  To preview the machine-readable output locally:
1159
1160
 
data/docs/docker.md CHANGED
@@ -10,7 +10,7 @@ execution when a Docker daemon is available.
10
10
  |------|--------|
11
11
  | Image name | `evaluator-sandbox` (`Constants::Sandbox::DOCKER_IMAGE_NAME`) |
12
12
  | Tags | `evaluator-sandbox:<SkillBench::VERSION>` and `evaluator-sandbox:latest` |
13
- | Base | `ruby:3.4-bookworm` (aligns with CI Ruby 3.4; 3.3 hosts still run evals via host Ruby for the orchestrator) |
13
+ | Base | `ruby:3.4-bookworm` (commands inside the container use Ruby 3.4; the gem also supports Ruby 3.3 and 4.0 on the host) |
14
14
  | Preinstalled | Ruby (from base), `git`, minimal Debian tools from base image |
15
15
  | Working directory | `/sandbox` (host sandbox dir is bind-mounted here read-write) |
16
16
  | Default process | `sleep infinity` — container stays up for `docker exec` |
@@ -6,13 +6,13 @@ Get started with Ruby Skill Bench in 5 minutes. No prior AI eval experience requ
6
6
 
7
7
  ## Prerequisites
8
8
 
9
- - Ruby 3.1+
9
+ - Ruby 3.3+
10
10
  - Bundler
11
11
 
12
12
  Not sure? Run:
13
13
 
14
14
  ```bash
15
- ruby --version # Should be 3.1 or higher
15
+ ruby --version # Should be 3.3 or higher
16
16
  bundle --version # Should print a version number
17
17
  ```
18
18
 
@@ -42,6 +42,14 @@ skill-bench init --openai
42
42
 
43
43
  This creates `skill-bench.json` with the OpenAI provider config. Use `--force` to overwrite.
44
44
 
45
+ Before running an eval, set your OpenAI key in the shell. Do not commit API keys to your repository:
46
+
47
+ ```bash
48
+ export SKILL_BENCH_OPENAI_API_KEY=your-api-key
49
+ ```
50
+
51
+ To try the commands without an API key or network access, initialize the offline mock provider instead: `skill-bench init --mock`. The mock provider is useful for learning the workflow; it does not measure a real model.
52
+
45
53
  **Available providers:** `--openai`, `--anthropic`, `--gemini`, `--ollama`, `--azure`, `--groq`, `--deepseek`, `--mistral`, `--opencode`, `--openrouter`, `--xai`, `--bedrock`, plus `--mock` for an offline config with no API key.
46
54
 
47
55
  > **What is `skill-bench.json`?** This is your config file. It stores your API key, chosen LLM model, timeout, and allowed shell commands. Think of it as `.env` but structured as JSON. You edit it; SkillBench reads it.
@@ -66,7 +74,7 @@ This creates `skills/my-service/SKILL.md` with a Rails service object template.
66
74
 
67
75
  **Example `SKILL.md`:**
68
76
 
69
- ```markdown
77
+ ````markdown
70
78
  # Service Object Skill
71
79
 
72
80
  ## Pattern
@@ -82,7 +90,7 @@ All service objects use the `.call` class method and return a standardized hash:
82
90
  1. Every `.rb` file begins with `# frozen_string_literal: true`
83
91
  2. Every public method has YARD docs (`@param`, `@return`, `@raise`)
84
92
  3. `rescue StandardError` blocks must log backtrace
85
- ```ruby
93
+ ````
86
94
 
87
95
  ---
88
96
 
@@ -21,10 +21,10 @@ module SkillBench
21
21
  # @param system_prompt [String] The system instruction for the LLM.
22
22
  # @param messages [Array<Hash>] The list of conversation messages.
23
23
  # @param tools [Array<Hash>] (optional) Array of tool definitions.
24
- # @param options [Hash] (optional) Additional provider-specific options.
24
+ # Additional keyword options are passed to the selected provider client.
25
25
  # @return [Hash] with :success [Boolean] and :response [Hash] keys.
26
- def self.call(system_prompt:, messages:, tools: [], **options)
27
- new(system_prompt: system_prompt, messages: messages, tools: tools, **options).call
26
+ def self.call(system_prompt:, messages:, tools: [], **)
27
+ new(system_prompt: system_prompt, messages: messages, tools: tools, **).call
28
28
  end
29
29
 
30
30
  # Initializes the client with validated parameters.
@@ -20,15 +20,16 @@ module SkillBench
20
20
  # @return [Hash]
21
21
  def call
22
22
  nums = Array(@totals).map { |total| Float(total) }
23
- return empty_result(count: nums.size) if nums.size < 2
23
+ count = nums.size
24
+ return empty_result(count: count) if count < 2
24
25
 
25
- mean = nums.sum / nums.size
26
- sample_variance = nums.sum { |value| (value - mean)**2 } / (nums.size - 1)
26
+ mean = nums.sum / count
27
+ sample_variance = nums.sum { |value| (value - mean)**2 } / (count - 1)
27
28
 
28
29
  {
29
30
  success: true,
30
31
  response: {
31
- n: nums.size,
32
+ n: count,
32
33
  mean: mean,
33
34
  stddev: Math.sqrt(sample_variance),
34
35
  spread: nums.max - nums.min
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'parallel'
5
+ require_relative 'task/directory_finder'
5
6
  require_relative 'task/evaluator'
6
7
  require_relative 'error_logger'
7
8
 
@@ -79,11 +80,7 @@ module SkillBench
79
80
  # @param root_path [Pathname] The root directory to search.
80
81
  # @return [Array<Pathname>] A list of task directory paths.
81
82
  def self.discover_task_dirs(root_path)
82
- if File.exist?(root_path.join('task.md'))
83
- [root_path]
84
- else
85
- Dir.glob(root_path.join('**/task.md')).map { |f| Pathname.new(f).parent }.uniq.sort
86
- end
83
+ Task::DirectoryFinder.call(root_path)
87
84
  end
88
85
  end
89
86
  end
@@ -4,7 +4,7 @@ require 'pathname'
4
4
  require 'parallel'
5
5
  require_relative 'runner_service'
6
6
  require_relative '../output_formatter'
7
- require_relative '../runner'
7
+ require_relative '../task/directory_finder'
8
8
 
9
9
  module SkillBench
10
10
  module Services
@@ -14,9 +14,7 @@ module SkillBench
14
14
  # {RunnerService} over each, returning an aggregate envelope with
15
15
  # per-eval results and a pass/fail summary.
16
16
  #
17
- # Discovery reuses {SkillBench::Runner.discover_task_dirs} but never
18
- # routes through the deprecated {SkillBench::Task::Evaluator}: each eval
19
- # is executed by the supported {RunnerService}.
17
+ # Each discovered eval is executed by the supported {RunnerService}.
20
18
  class BatchRunnerService
21
19
  # Default directory scanned for evals when none is supplied.
22
20
  DEFAULT_EVALS_DIR = 'evals'
@@ -80,7 +78,7 @@ module SkillBench
80
78
  #
81
79
  # @return [Array<Pathname>] Directories that contain a task.md
82
80
  def discover_eval_dirs
83
- SkillBench::Runner.discover_task_dirs(Pathname.new(evals_dir))
81
+ Task::DirectoryFinder.call(Pathname.new(evals_dir))
84
82
  end
85
83
 
86
84
  # Runs every eval directory through {RunnerService} concurrently.
@@ -70,7 +70,7 @@ module SkillBench
70
70
  #
71
71
  # @raise [SystemCallError] when file write operation fails
72
72
  def write_json_file
73
- File.write(@output_path, JSON.generate(@result, pretty: true))
73
+ File.write(@output_path, JSON.pretty_generate(@result))
74
74
  end
75
75
  end
76
76
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
5
+ module SkillBench
6
+ module Task
7
+ # Finds evaluation task directories under a root path.
8
+ class DirectoryFinder
9
+ # Finds the root task or all nested task directories in sorted order.
10
+ #
11
+ # @param root_path [Pathname] Directory to search.
12
+ # @return [Array<Pathname>] Directories containing a task.md file.
13
+ def self.call(root_path)
14
+ return [root_path] if File.exist?(root_path.join('task.md'))
15
+
16
+ Dir.glob(root_path.join('**/task.md')).map { |path| Pathname.new(path).parent }.uniq.sort
17
+ end
18
+ end
19
+ end
20
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module SkillBench
4
4
  # The current gem version.
5
- VERSION = '1.4.0'
5
+ VERSION = '2.0.0'
6
6
  end
data/lib/skill_bench.rb CHANGED
@@ -34,6 +34,7 @@ require_relative 'skill_bench/agent/react_agent'
34
34
  require_relative 'skill_bench/task'
35
35
  require_relative 'skill_bench/task/evaluator'
36
36
  require_relative 'skill_bench/task/file_reader'
37
+ require_relative 'skill_bench/runner'
37
38
 
38
39
  # Evaluation orchestration
39
40
  require_relative 'skill_bench/evaluation'
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-skill-bench
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ismael Marin
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-09-14 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: cgi
@@ -44,34 +43,28 @@ dependencies:
44
43
  requirements:
45
44
  - - "~>"
46
45
  - !ruby/object:Gem::Version
47
- version: '2.21'
48
- - - ">="
49
- - !ruby/object:Gem::Version
50
- version: 2.21.2
46
+ version: '3.0'
51
47
  type: :runtime
52
48
  prerelease: false
53
49
  version_requirements: !ruby/object:Gem::Requirement
54
50
  requirements:
55
51
  - - "~>"
56
52
  - !ruby/object:Gem::Version
57
- version: '2.21'
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: 2.21.2
53
+ version: '3.0'
61
54
  - !ruby/object:Gem::Dependency
62
55
  name: parallel
63
56
  requirement: !ruby/object:Gem::Requirement
64
57
  requirements:
65
58
  - - "~>"
66
59
  - !ruby/object:Gem::Version
67
- version: '1.26'
60
+ version: '2.0'
68
61
  type: :runtime
69
62
  prerelease: false
70
63
  version_requirements: !ruby/object:Gem::Requirement
71
64
  requirements:
72
65
  - - "~>"
73
66
  - !ruby/object:Gem::Version
74
- version: '1.26'
67
+ version: '2.0'
75
68
  description: |
76
69
  ruby-skill-bench orchestrates evaluation runs of AI coding agents
77
70
  inside isolated git sandboxes, then scores the results using deterministic
@@ -225,6 +218,7 @@ files:
225
218
  - lib/skill_bench/services/variant_parser.rb
226
219
  - lib/skill_bench/services/variant_resolver.rb
227
220
  - lib/skill_bench/task.rb
221
+ - lib/skill_bench/task/directory_finder.rb
228
222
  - lib/skill_bench/task/evaluator.rb
229
223
  - lib/skill_bench/task/file_reader.rb
230
224
  - lib/skill_bench/tools.rb
@@ -245,7 +239,6 @@ licenses:
245
239
  metadata:
246
240
  rubygems_mfa_required: 'true'
247
241
  source_code_uri: https://github.com/igmarin/ruby-skill-bench
248
- post_install_message:
249
242
  rdoc_options: []
250
243
  require_paths:
251
244
  - lib
@@ -253,15 +246,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
253
246
  requirements:
254
247
  - - ">="
255
248
  - !ruby/object:Gem::Version
256
- version: '3.1'
249
+ version: '3.3'
257
250
  required_rubygems_version: !ruby/object:Gem::Requirement
258
251
  requirements:
259
252
  - - ">="
260
253
  - !ruby/object:Gem::Version
261
254
  version: '0'
262
255
  requirements: []
263
- rubygems_version: 3.5.22
264
- signing_key:
256
+ rubygems_version: 4.0.21
265
257
  specification_version: 4
266
258
  summary: The evaluation engine for AI Agent Skills benchmarking.
267
259
  test_files: []