From 89b440a62c6178f3af49059142c7e71474670b9d Mon Sep 17 00:00:00 2001 From: Steve Polito Date: Mon, 27 Apr 2026 06:01:18 -0400 Subject: [PATCH] Add simple AI Harness Relates to https://github.com/thoughtbot/suspenders/discussions/1350 and https://github.com/thoughtbot/suspenders/discussions/1351. We introduced [thoughtbot agents rules](https://github.com/thoughtbot/guides/pull/783) to our guides a few months ago. This commit simply pulls those files into newly generated Suspenders applications. There's a case to be made that these should be kept separate, but I like having a single source of truth. --- .github/workflows/main.yml | 7 ++++++ FEATURES.md | 22 +++++++++++++++++++ NEWS.md | 2 ++ lib/templates/web.rb | 44 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 05404e00..3f714b0b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -88,6 +88,13 @@ jobs: end end EOF + - name: Verify AI harness files exist + working-directory: /tmp/test_app + run: | + test -f .claude/CLAUDE.md || (echo ".claude/CLAUDE.md not found" && exit 1) + test -d .claude/rules || (echo ".claude/rules directory not found" && exit 1) + test "$(ls -A .claude/rules)" || (echo ".claude/rules is empty" && exit 1) + test ! -f .claude/rules/README.md || (echo ".claude/rules/README.md should not be downloaded" && exit 1) - name: Run tests in generated app env: RAILS_ENV: test diff --git a/FEATURES.md b/FEATURES.md index 8c307a1d..e9b17598 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -181,3 +181,25 @@ Configuration can be found at `config/initializers/inline_svg.rb` [lang]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang [title]: https://github.com/calebhearth/title [Prefetch]: https://turbo.hotwired.dev/handbook/drive#prefetching-links-on-hover + +## AI Harness + +Downloads [AI rules][] from [thoughtbot/guides][] into `.claude/` at app +generation time: + +- `.claude/CLAUDE.md` - a project brief that AI assistants load as context. +- `.claude/rules/` - coding standards for models, controllers, testing, + security, views, and database conventions. + +Because the files are fetched from GitHub when the app is generated, they +always reflect the latest version of the guides at that point in time. + +### Customize `CLAUDE.md` + +The generated `.claude/CLAUDE.md` is a starting point. Update it with +project-specific details so AI assistants have accurate context for your +application — including domain language, architectural decisions, and any +conventions that diverge from the defaults in `.claude/rules/`. + +[AI rules]: https://github.com/thoughtbot/guides/tree/main/rails/ai-rules +[thoughtbot/guides]: https://github.com/thoughtbot/guides diff --git a/NEWS.md b/NEWS.md index 49c4b45e..bb310052 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ Unreleased +* Added: AI harness. Downloads `.claude/CLAUDE.md` and `.claude/rules/` from [thoughtbot/guides](https://github.com/thoughtbot/guides/tree/main/rails/ai-rules). + 20260325.0 (March 25, 2026) * Added: Hotwire Spark for live reloading in development. diff --git a/lib/templates/web.rb b/lib/templates/web.rb index e50f6596..6c821530 100644 --- a/lib/templates/web.rb +++ b/lib/templates/web.rb @@ -1,4 +1,6 @@ require "suspenders/version" +require "net/http" +require "json" # Methods like `copy_file` will accept relative paths to the template's location. def source_paths @@ -69,6 +71,7 @@ def install_gems # Finalization run_migrations update_readme + add_ai_harness lint_codebase commit_final_application_state @@ -516,6 +519,28 @@ def update_readme [lang]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang [title]: https://github.com/calebhearth/title [Prefetch]: https://turbo.hotwired.dev/handbook/drive#prefetching-links-on-hover + + ## AI Harness + + Downloads [AI rules][] from [thoughtbot/guides][] into `.claude/` at app + generation time: + + - `.claude/CLAUDE.md` - a project brief that AI assistants load as context. + - `.claude/rules/` - coding standards for models, controllers, testing, + security, views, and database conventions. + + Because the files are fetched from GitHub when the app is generated, they + always reflect the latest version of the guides at that point in time. + + ### Customize `CLAUDE.md` + + The generated `.claude/CLAUDE.md` is a starting point. Update it with + project-specific details so AI assistants have accurate context for your + application — including domain language, architectural decisions, and any + conventions that diverge from the defaults in `.claude/rules/`. + + [AI rules]: https://github.com/thoughtbot/guides/tree/main/rails/ai-rules + [thoughtbot/guides]: https://github.com/thoughtbot/guides MARKDOWN end end @@ -524,6 +549,25 @@ def lint_codebase run "bin/rubocop -a" end +def add_ai_harness + base_url = "https://raw.githubusercontent.com/thoughtbot/guides/main/rails/ai-rules" + api_url = "https://api.github.com/repos/thoughtbot/guides/contents/rails/ai-rules/rules" + + empty_directory ".claude" + empty_directory ".claude/rules" + + get "#{base_url}/CLAUDE.md", ".claude/CLAUDE.md" + + response = Net::HTTP.get(URI(api_url)) + files = JSON.parse(response) + files.each do |file| + next unless file["type"] == "file" + next if file["name"].casecmp?("README.md") + + get "#{base_url}/rules/#{file["name"]}", ".claude/rules/#{file["name"]}" + end +end + def commit_final_application_state git add: ".", commit: %(-m 'Changes introduced by Suspenders version #{Suspenders::VERSION}') unless ENV["CI"] end