Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
44 changes: 44 additions & 0 deletions lib/templates/web.rb
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -69,6 +71,7 @@ def install_gems
# Finalization
run_migrations
update_readme
add_ai_harness
lint_codebase
commit_final_application_state

Expand Down Expand Up @@ -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
Expand All @@ -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"
Comment on lines +556 to +559

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One issue here is this is Claude-specific. That works for thoughtbot, but do we want to support other services?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI it's being discussed here thoughtbot/guides#786 (comment)


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
Comment thread
stevepolitodesign marked this conversation as resolved.
end

def commit_final_application_state
git add: ".", commit: %(-m 'Changes introduced by Suspenders version #{Suspenders::VERSION}') unless ENV["CI"]
end
Expand Down
Loading