Skip to content

Latest commit

 

History

History
234 lines (164 loc) · 7.94 KB

File metadata and controls

234 lines (164 loc) · 7.94 KB

AGENTS.md - Development Guide

🎯 Project Overview

This project is a RubyGem managed with the kettle-rb toolchain.

Minimum Supported Ruby: See the gemspec required_ruby_version constraint. Local Development Ruby: See .tool-versions for the version used in local development (typically the latest stable Ruby).

Modular Gemfile Architecture

Gemfiles are split into modular components under gemfiles/modular/. Each component handles a specific concern (coverage, style, debug, etc.). The main Gemfile loads these modular components via eval_gemfile. Gemfiles in the project, including modular ones, can utilize a *_local.gemfile counterpart pattern enabled via an ENV flag. This uses nomono to load sibling gems in the same workspace.

⚠️ AI Agent Terminal Limitations

Use mise for Project Environment

CRITICAL: The canonical project environment lives in mise.toml, with local overrides in .env.local loaded via dotenvy.

⚠️ Watch for trust prompts: After editing mise.toml or .env.local, mise may require trust to be refreshed before commands can load the project environment. Until that trust step is handled, commands can appear hung or produce no output, which can look like terminal access is broken.

Recovery rule: If a mise exec command goes silent or appears hung, assume mise trust is the first thing to check. Recover by running:

mise trust -C /path/to/project
mise exec -C /path/to/project -- bundle exec rspec

Do this before spending time on unrelated debugging; in this workspace pattern, silent mise commands are usually a trust problem first.

CORRECT — Run self-contained commands with mise exec:

mise exec -C /path/to/project -- bundle exec rspec

CORRECT — If you need shell syntax first, load the environment in the same command:

eval "$(mise env -C /path/to/project -s bash)" && bundle exec rspec

WRONG — Do not rely on a previous command changing directories:

cd /path/to/project
bundle exec rspec

WRONG — A chained cd does not give directory-change hooks time to update the environment:

cd /path/to/project && bundle exec rspec

Prefer Internal Tools Over Terminal

PREFERRED — Use internal tools:

  • grep_search instead of grep command
  • file_search instead of find command
  • read_file instead of cat command
  • list_dir instead of ls command
  • replace_string_in_file or create_file instead of sed / manual editing

AVOID when possible:

  • run_in_terminal for information gathering

Only use terminal for:

  • Running tests (bundle exec rspec)
  • Installing dependencies (bundle install)
  • Simple commands that do not require much shell escaping
  • Running scripts (prefer writing a script over a complicated command with shell escaping)

When you do run tests, keep the full output visible so you can inspect failures completely.

🏗️ Architecture

Toolchain Dependencies

This gem is part of the kettle-rb ecosystem. Key development tools:

Tool Purpose
kettle-dev Development dependency: Rake tasks, release tooling, CI helpers
kettle-test Test infrastructure: RSpec helpers, stubbed_env, timecop
kettle-jem Template management and gem scaffolding

Executables (from kettle-dev)

Executable Purpose
kettle-release Full gem release workflow
kettle-pre-release Pre-release validation
kettle-changelog Changelog generation
kettle-dvcs DVCS (git) workflow automation
kettle-commit-msg Commit message validation
kettle-check-eof EOF newline validation

📁 Project Structure

lib/
├── <gem_namespace>/           # Main library code
│   └── version.rb             # Version constant (managed by kettle-release)
spec/
├── fixtures/                  # Test fixture files (NOT auto-loaded)
├── support/
│   ├── classes/               # Helper classes for specs
│   └── shared_contexts/       # Shared RSpec contexts
├── spec_helper.rb             # RSpec configuration (loaded by .rspec)
gemfiles/
├── modular/                   # Modular Gemfile components
│   ├── coverage.gemfile       # SimpleCov dependencies
│   ├── debug.gemfile          # Debugging tools
│   ├── documentation.gemfile  # YARD/documentation
│   ├── optional.gemfile       # Optional dependencies
│   ├── rspec.gemfile          # RSpec testing
│   ├── style.gemfile          # RuboCop/linting
│   └── x_std_libs.gemfile     # Extracted stdlib gems
├── ruby_*.gemfile             # Per-Ruby-version Appraisal Gemfiles
└── Appraisal.root.gemfile     # Root Gemfile for Appraisal builds
.git-hooks/
├── commit-msg                 # Commit message validation hook
├── prepare-commit-msg         # Commit message preparation
├── commit-subjects-goalie.txt # Commit subject prefix filters
└── footer-template.erb.txt    # Commit footer ERB template

🔧 Development Workflows

Running Commands

Always make commands self-contained. Use mise exec -C /home/pboling/src/kettle-rb/prism-merge -- ... so the command gets the project environment in the same invocation. If the command is complicated write a script in local tmp/ and then run the script.

Running Tests

Full suite spec runs:

mise exec -C /path/to/project -- bundle exec rspec

For single file, targeted, or partial spec runs the coverage threshold must be disabled. Use the K_SOUP_COV_MIN_HARD=false environment variable to disable hard failure:

mise exec -C /path/to/project -- env K_SOUP_COV_MIN_HARD=false bundle exec rspec spec/path/to/spec.rb

Coverage Reports

mise exec -C /path/to/project -- bin/rake coverage
mise exec -C /path/to/project -- bin/kettle-soup-cover -d

Key ENV variables (set in mise.toml, with local overrides in .env.local):

  • K_SOUP_COV_DO=true – Enable coverage
  • K_SOUP_COV_MIN_LINE – Line coverage threshold
  • K_SOUP_COV_MIN_BRANCH – Branch coverage threshold
  • K_SOUP_COV_MIN_HARD=true – Fail if thresholds not met

Code Quality

mise exec -C /path/to/project -- bundle exec rake reek
mise exec -C /path/to/project -- bundle exec rubocop-gradual

Releasing

bin/kettle-pre-release    # Validate everything before release
bin/kettle-release        # Full release workflow

📝 Project Conventions

Freeze Block Preservation

Template updates preserve custom code wrapped in freeze blocks:

# kettle-jem:freeze
# ... custom code preserved across template runs ...
# kettle-jem:unfreeze

Modular Gemfile Architecture

Gemfiles are split into modular components under gemfiles/modular/. Each component handles a specific concern (coverage, style, debug, etc.). The main Gemfile loads these modular components via eval_gemfile.

Forward Compatibility with **options

CRITICAL: All constructors and public API methods that accept keyword arguments MUST include **options as the final parameter for forward compatibility.

🧪 Testing Patterns

Test Infrastructure

  • Uses kettle-test for RSpec helpers (stubbed_env, block_is_expected, silent_stream, timecop)
  • Uses Dir.mktmpdir for isolated filesystem tests
  • Spec helper is loaded by .rspec — never add require "spec_helper" to spec files

Environment Variable Helpers

before do
  stub_env("MY_ENV_VAR" => "value")
end

before do
  hide_env("HOME", "USER")
end

Dependency Tags

Use dependency tags to conditionally skip tests when optional dependencies are not available:

RSpec.describe SomeClass, :prism_merge do
  # Skipped if prism-merge is not available
end

🚫 Common Pitfalls

  1. NEVER pipe test output through head/tail — Run tests without truncation so you can inspect the full output.