Skip to content

Commit 8787089

Browse files
Add simple AI Harness
Relates to #1350 and #1351. We introduced [thoughtbot agents rules](thoughtbot/guides#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.
1 parent 1a23812 commit 8787089

4 files changed

Lines changed: 44 additions & 0 deletions

File tree

.github/workflows/main.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ jobs:
8888
end
8989
end
9090
EOF
91+
- name: Verify AI harness files exist
92+
working-directory: /tmp/test_app
93+
run: |
94+
test -f .claude/CLAUDE.md || (echo ".claude/CLAUDE.md not found" && exit 1)
95+
test -d .claude/rules || (echo ".claude/rules directory not found" && exit 1)
96+
test "$(ls -A .claude/rules)" || (echo ".claude/rules is empty" && exit 1)
9197
- name: Run tests in generated app
9298
env:
9399
RAILS_ENV: test

FEATURES.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,18 @@ Configuration can be found at `config/initializers/inline_svg.rb`
181181
[lang]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang
182182
[title]: https://github.com/calebhearth/title
183183
[Prefetch]: https://turbo.hotwired.dev/handbook/drive#prefetching-links-on-hover
184+
185+
## AI Harness
186+
187+
Downloads [AI rules][] from [thoughtbot/guides][] into `.claude/` at app
188+
generation time. This includes a `CLAUDE.md` project brief and a `rules/`
189+
directory with coding standards for models, controllers, testing, security,
190+
views, and database conventions.
191+
192+
Because the files are fetched from GitHub when the app is generated, they
193+
always reflect the latest version of the guides at that point in time.
194+
195+
However, it is encouraged to update these files based on project sepcific requirenments.
196+
197+
[AI rules]: https://github.com/thoughtbot/guides/tree/main/rails/ai-rules
198+
[thoughtbot/guides]: https://github.com/thoughtbot/guides

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
Unreleased
22

3+
* Added: AI harness. Downloads `.claude/CLAUDE.md` and `.claude/rules/` from [thoughtbot/guides](https://github.com/thoughtbot/guides/tree/main/rails/ai-rules).
4+
35
20260325.0 (March 25, 2026)
46

57
* Added: Hotwire Spark for live reloading in development.

lib/templates/web.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
require "suspenders/version"
22
require "suspenders/gemfile/group_merger"
3+
require "net/http"
4+
require "json"
35

46
# Methods like `copy_file` will accept relative paths to the template's location.
57
def source_paths
@@ -71,6 +73,7 @@ def install_gems
7173
# Finalization
7274
run_migrations
7375
update_readme
76+
add_ai_harness
7477
lint_codebase
7578
commit_final_application_state
7679

@@ -532,6 +535,24 @@ def lint_codebase
532535
run "bin/rubocop -a"
533536
end
534537

538+
def add_ai_harness
539+
base_url = "https://raw.githubusercontent.com/thoughtbot/guides/main/rails/ai-rules"
540+
api_url = "https://api.github.com/repos/thoughtbot/guides/contents/rails/ai-rules/rules"
541+
542+
empty_directory ".claude"
543+
empty_directory ".claude/rules"
544+
545+
get "#{base_url}/CLAUDE.md", ".claude/CLAUDE.md"
546+
547+
response = Net::HTTP.get(URI(api_url))
548+
files = JSON.parse(response)
549+
files.each do |file|
550+
next unless file["type"] == "file"
551+
552+
get "#{base_url}/rules/#{file["name"]}", ".claude/rules/#{file["name"]}"
553+
end
554+
end
555+
535556
def commit_final_application_state
536557
git add: ".", commit: %(-m 'Changes introduced by Suspenders version #{Suspenders::VERSION}') unless ENV["CI"]
537558
end

0 commit comments

Comments
 (0)