Development Guide¶
Welcome to the SharedTools development guide. This section covers everything you need to know to contribute to SharedTools, understand its architecture, and develop new tools.
Quick Start for Contributors¶
# Clone the repository
git clone https://github.com/madbomber/shared_tools.git
cd shared_tools
# Install dependencies
bundle install
# Run tests
bundle exec rspec
# Check test coverage
open coverage/index.html
Documentation Structure¶
Architecture¶
Deep dive into SharedTools architecture:
- Module organization and Zeitwerk autoloading
- Tool hierarchy and inheritance
- Facade pattern implementation
- Driver interface design
- Authorization system
- Framework detection and compatibility
Contributing¶
Guidelines for contributing:
- Code style and conventions
- Git workflow and branch strategy
- Pull request process
- Issue reporting
- Adding new tools
- Writing documentation
- Community guidelines
Testing¶
Comprehensive testing guide:
- Test structure and organization
- Using RSpec effectively
- Mock drivers and fixtures
- Test coverage requirements
- Integration testing
- Testing LLM interactions
- Performance testing
Changelog¶
Version history and migration guides:
- Current version: 0.2.1
- Breaking changes
- New features
- Bug fixes
- Deprecations
- Migration guides
Development Setup¶
Prerequisites¶
- Ruby 3.0 or higher
- Bundler
- Git
Optional Dependencies¶
For full functionality, install:
# Browser automation
gem install watir selenium-webdriver
# Database support
gem install sqlite3 pg
# PDF processing
gem install pdf-reader
# Development tools
gem install rubocop yard
Project Structure¶
shared_tools/
├── lib/
│ └── shared_tools/
│ ├── tools/ # Tool implementations
│ │ ├── browser/ # Browser sub-tools
│ │ ├── database/ # Database drivers
│ │ ├── disk/ # Disk drivers
│ │ ├── computer/ # Computer drivers
│ │ ├── eval/ # Eval sub-tools
│ │ └── doc/ # Doc sub-tools
│ └── shared_tools.rb # Main module
├── examples/ # Usage examples
├── test/ # Test files
└── docs/ # Documentation
Key Files¶
lib/shared_tools.rb: Main module with authorization systemlib/shared_tools/tools/browser_tool.rb: BrowserTool facadelib/shared_tools/tools/disk_tool.rb: DiskTool facadelib/shared_tools/tools/database_tool.rb: DatabaseTool facadeshared_tools.gemspec: Gem specification
Development Workflow¶
1. Pick an Issue or Feature¶
- Check GitHub issues for open items
- Comment on the issue to claim it
- Or create a new issue to discuss your idea
2. Create a Branch¶
3. Develop with TDD¶
Write tests first:
# spec/shared_tools/tools/my_new_tool_spec.rb
RSpec.describe SharedTools::Tools::MyNewTool do
describe "#execute" do
it "performs the action" do
tool = described_class.new
result = tool.execute(action: "test")
expect(result).to eq("expected")
end
end
end
Then implement:
# lib/shared_tools/tools/my_new_tool.rb
module SharedTools
module Tools
class MyNewTool < ::RubyLLM::Tool
def self.name = 'my_new_tool'
description "Tool description"
param :action, desc: "Action to perform"
def execute(action:)
# Implementation
end
end
end
end
4. Run Tests¶
# Run all tests
bundle exec rspec
# Run specific test
bundle exec rspec spec/shared_tools/tools/my_new_tool_spec.rb
# Run with coverage
COVERAGE=true bundle exec rspec
5. Check Code Style¶
6. Update Documentation¶
- Add/update YARD comments in code
- Update relevant markdown documentation
- Add examples if applicable
7. Commit Changes¶
Follow Conventional Commits:
feat:New featurefix:Bug fixdocs:Documentation onlytest:Adding testsrefactor:Code refactoringchore:Maintenance tasks
8. Push and Create PR¶
Then create a Pull Request on GitHub.
Adding a New Tool¶
Step-by-Step Guide¶
- Create the tool file:
# lib/shared_tools/tools/my_tool.rb
module SharedTools
module Tools
class MyTool < ::RubyLLM::Tool
def self.name = 'my_tool'
description <<~TEXT
What this tool does.
## Usage
- Example usage
TEXT
param :action, desc: "Action to perform"
param :required_param, desc: "Required parameter"
param :optional_param, desc: "Optional parameter"
def initialize(driver: nil, logger: nil)
@driver = driver
@logger = logger || RubyLLM.logger
end
def execute(action:, required_param:, optional_param: nil)
@logger&.info("Executing #{action}")
# Implementation
end
end
end
end
- Create tests:
# spec/shared_tools/tools/my_tool_spec.rb
require 'spec_helper'
RSpec.describe SharedTools::Tools::MyTool do
let(:tool) { described_class.new }
describe "#execute" do
it "works" do
result = tool.execute(
action: "test",
required_param: "value"
)
expect(result).to be_truthy
end
end
end
- Add example:
# examples/my_tool_example.rb
require 'bundler/setup'
require 'shared_tools'
tool = SharedTools::Tools::MyTool.new
result = tool.execute(
action: "demo",
required_param: "test"
)
puts result
-
Update documentation:
-
Add tool to
docs/tools/my-tool.md - Reference in
docs/api/index.md - Add to examples index
Testing Guidelines¶
Test Organization¶
RSpec.describe SharedTools::Tools::MyTool do
# Context for different scenarios
context "when action is valid" do
it "performs the action" do
# Test implementation
end
end
context "when action is invalid" do
it "raises an error" do
expect {
tool.execute(action: "invalid")
}.to raise_error(ArgumentError)
end
end
# Test parameter validation
describe "parameter validation" do
it "requires action parameter" do
expect {
tool.execute(required_param: "value")
}.to raise_error(ArgumentError, /action/)
end
end
# Test different actions
describe "actions" do
describe "test_action" do
it "returns expected result" do
result = tool.execute(action: "test_action", required_param: "value")
expect(result).to eq("expected")
end
end
end
end
Using Mock Drivers¶
let(:mock_driver) do
instance_double(
SharedTools::Tools::Browser::BaseDriver,
goto: "navigated",
html: "<html>test</html>",
click: "clicked"
)
end
let(:tool) { described_class.new(driver: mock_driver) }
Code Style¶
Ruby Style Guide¶
Follow the Ruby Style Guide:
- Use 2 spaces for indentation
- Maximum line length: 120 characters
- Use snake_case for methods and variables
- Use CamelCase for classes and modules
Documentation Style¶
Use YARD for code documentation:
# Description of what the method does
#
# @param action [String] the action to perform
# @param options [Hash] optional parameters
# @option options [String] :url URL to visit
# @option options [Integer] :timeout timeout in seconds
#
# @return [String] result of the operation
#
# @raise [ArgumentError] if action is invalid
#
# @example Basic usage
# tool.execute(action: "visit", options: { url: "https://example.com" })
def execute(action:, options: {})
# Implementation
end
Performance Considerations¶
- Use lazy loading for sub-tools and drivers
- Cache expensive computations
- Avoid unnecessary object creation
- Use connection pooling for databases
- Profile code with
ruby-profif needed
Security Considerations¶
- Validate all user inputs
- Use authorization system for dangerous operations
- Sanitize SQL to prevent injection
- Escape HTML/CSS selectors
- Don't log sensitive information
- Use secure temp files
Release Process¶
- Update version in
lib/shared_tools/tools/version.rb - Update
CHANGELOG.md - Run full test suite
- Commit changes
- Tag release:
git tag v0.x.x - Push:
git push && git push --tags - Build gem:
gem build shared_tools.gemspec - Publish:
gem push shared_tools-0.x.x.gem
Getting Help¶
- GitHub Discussions: Ask questions
- GitHub Issues: Report bugs
- Code Review: Request feedback on PRs
- Documentation: Read the docs
Resources¶
Next Steps¶
- Read the Architecture Guide
- Review Contributing Guidelines
- Learn about Testing Strategies
- Check the Changelog