Improve Claude Code setup#1378
Conversation
Rootstrap's tech-guides conventions when Claude Code edits Ruby, Rails, or RSpec code in projects bootstrapped from this template
- pr-size-checker (agent): analyzes the current branch's diff against its base and recommends splitting into smaller PRs when the effective added lines exceed ~400, while respecting Rails-specific groupings (model+migration, routes+controller, factories with new models). - github-pr-formatting (rule): single source of truth for PR creation — walks through filling each section of the repo's PR template (Board, Description, Notes, Tasks, Risk, Preview), defines the title format ([TICKET-ID] when applicable), and documents GitHub markdown gotchas. - create-pr (command): workflow for opening a PR — runs the size check, prepares the branch, gathers commit info, and invokes github-pr-formatting to fill the body.
- Adds .claude/agents/code-reviewer.md, a read-only review subagent that preloads the ruby/rails/rspec convention skills and applies them to diffs against the base branch. Restricted via the `tools:` whitelist to read-only operations. - Removes the Timecop guidance from rspec-conventions: this template uses Rails' built-in `freeze_time` / `travel_to` (configured in spec/rails_helper.rb), and Timecop is not in the bundle. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
|
|
||
| ## What this repo is | ||
|
|
||
| Rootstrap's Rails API template — a Rails 8.1 / Ruby 4.0 boilerplate for JSON APIs. It is meant to be cloned and renamed via `bin/bootstrap.sh --name=<project>`, which `sed`s `rails_api_base` to your project name across the codebase. The template ships with two parallel surfaces: |
There was a problem hiding this comment.
NIT
Is there a way to ensure this section gets updated whenever a new project is started?
Maybe it doesn't belong here, and it fits better somewhere else, like in the Foundation checklist.
There was a problem hiding this comment.
Pull request overview
Adds Claude Code project guidance for the rails_api_base template, including repository context, Ruby/Rails/RSpec conventions, and standardized PR creation/review workflows.
Changes:
- Introduces
CLAUDE.mdas the main Claude Code entry point and documents common repo commands/architecture. - Adds Claude Code skills (
ruby-conventions,rails-conventions,rspec-conventions) plus agents (code-reviewer,pr-size-checker) and acreate-prcommand/ruleset. - Updates the README with Claude Code setup information.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Documents the presence and purpose of .claude/skills/* for Claude Code users. |
| CLAUDE.md | Adds repository-wide Claude Code guidance (commands, architecture, conventions, PR workflow). |
| .claude/skills/ruby-conventions/SKILL.md | Adds Rootstrap Ruby style guidance as an auto-activated Claude Code skill. |
| .claude/skills/rails-conventions/SKILL.md | Adds Rootstrap Rails conventions as an auto-activated Claude Code skill. |
| .claude/skills/rspec-conventions/SKILL.md | Adds Rootstrap RSpec conventions as an auto-activated Claude Code skill. |
| .claude/rules/github-pr-formatting.md | Defines canonical PR body formatting rules for consistent GitHub rendering. |
| .claude/commands/create-pr.md | Adds a standardized PR creation workflow referencing the formatting rules. |
| .claude/agents/pr-size-checker.md | Adds an agent spec to assess PR size and propose logical splits. |
| .claude/agents/code-reviewer.md | Adds an agent spec to review diffs against project conventions and quality checks. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 3. **If the current branch tracks an upstream**, infer from merge base: | ||
| ```bash | ||
| git merge-base HEAD main 2>/dev/null | ||
| git merge-base HEAD main 2>/dev/null | ||
| ``` |
There was a problem hiding this comment.
Since git merge-base prints the merge-base SHA to stdout, running it without assigning the result does not affect the later git diff $BASE...HEAD call. As far as I can tell, $BASE still remains set to main.
If the intent is to handle cases where HEAD may not be directly comparable to main, we could capture the merge base instead:
BASE=$(git merge-base HEAD main 2>/dev/null || echo "main")Otherwise, I think the duplicate commands can just be removed.
| ## Date & Time | ||
| - `Time.now` over `Time.new`; use `Date` or `Time`, not `DateTime`. | ||
| - (See also `rails-conventions` — in Rails, use `Time.zone.now`/`Time.current`.) |
| --- | ||
| name: rails-conventions | ||
| description: Rootstrap Rails conventions. Use when writing, reviewing, or editing any Rails code — controllers, models, migrations, routes, views, mailers, initializers, locale files, or Rails config. Covers routing, ActiveRecord, migrations, i18n, time zones, mailers, assets, Bundler groups, and logging. | ||
| --- |
There was a problem hiding this comment.
nit: Since CLAUDE.md mentions that project-level skills auto-activate based on the files being edited, maybe we could add paths: to the skill frontmatter to make that behavior explicit and deterministic.
That way, activation is driven by file glob matches rather than relying only on whether the agent considers the skill relevant from the description.
Reference: https://code.claude.com/docs/en/skills#frontmatter-reference
Example:
---
name: ruby-conventions
description: Use when writing, reviewing, or editing Ruby files.
paths: "**/*.rb,**/*.rake,**/Gemfile,**/Rakefile,**/*.gemspec"
---| @@ -0,0 +1,107 @@ | |||
| # CLAUDE.md | |||
There was a problem hiding this comment.
Would it be useful to include a starter .claude/settings.json with hooks for the workflow described in CLAUDE.md?
Right now, CLAUDE.md documents steps like loading the relevant skill, running checks, and using the reviewer agent, but those seem to rely on the agent following the instructions manually. A small hooks template could make the intended workflow easier to adopt consistently across projects.
Reference: https://code.claude.com/docs/en/hooks
For example:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bundle exec rubocop",
"timeout": 30,
"statusMessage": "Running RuboCop..."
}
]
}
]
}
}Even if we do not want to enforce hooks by default, documenting this as an optional per-project setup could help clarify how teams can make the conventions more deterministic.
| description: "Use proactively after completing code changes, or when the user asks for a code review. Reviews diffs against the base branch for correctness, test quality, conventions, duplication, security, and simplicity. Returns structured findings." | ||
| model: sonnet | ||
| maxTurns: 10 | ||
| tools: Read, Grep, Glob, Bash, WebFetch |
There was a problem hiding this comment.
Would WebFetch be needed for the code-reviewer agent?
I noticed the agent declares:
tools: Read, Grep, Glob, Bash, WebFetchbut I could not find anything in the agent instructions that requires fetching external URLs. Since this agent seems focused on reviewing the local codebase, would it be safer to keep the tool list limited to only what it needs?
For example:
tools: Read, Grep, Glob, BashThis would reduce the available surface area while still allowing the agent to read, search, inspect, and run local review commands. Feel free to ignore this if I’m missing a use case for WebFetch here.
| 3. **If the current branch tracks an upstream**, infer from merge base: | ||
| ```bash | ||
| git merge-base HEAD main 2>/dev/null | ||
| git merge-base HEAD main 2>/dev/null | ||
| ``` |
There was a problem hiding this comment.
Since git merge-base prints the merge-base SHA to stdout, running it without assigning the result does not affect the later git diff $BASE...HEAD call. As far as I can tell, $BASE still remains set to main.
If the intent is to handle cases where HEAD may not be directly comparable to main, we could capture the merge base instead:
BASE=$(git merge-base HEAD main 2>/dev/null || echo "main")Otherwise, I think the duplicate commands can just be removed.
| ### 5. Create PR | ||
|
|
||
| ```bash | ||
| gh pr create --title "[{TICKET-ID}] {Concise description}" --body "{BODY}" --base main |
There was a problem hiding this comment.
nit: create-pr.md currently hardcodes main as the PR base branch:
gh pr create --title "..." --body "..." --base mainSince this template may be used by teams with a different default branch, such as develop or master, it might be safer to resolve the repository default branch dynamically instead of assuming main.
For example:
BASE_BRANCH=$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name' 2>/dev/null || echo "main")
gh pr create --title "..." --body "..." --base "$BASE_BRANCH"This would keep the command aligned with each repository’s actual default branch and avoid creating PRs against the wrong base by default.
| - Use **Faker** for fake data; **Database Cleaner** keeps state isolated. | ||
|
|
||
| ## Mocking / Stubbing / Doubles | ||
| - Use mocks/stubs sparingly — favor them in isolated/behavioral specs, not integration specs. |
There was a problem hiding this comment.
nice, I would also add something like:
- Avoid
allow_any_instance_of, as it stubs the method on every instance of the class, decoupled from which instance is actually used, and masks real interaction bugs. Prefer stubbing/mocking the specific instance. (and an example maybe)
| - Align multi-line method args after `(`, OR single-indent with `)` on its own line (avoid "double indent"). | ||
| - For `case`/`if` result assignment, either align branches under the keyword or break with `kind =` on its own line. | ||
|
|
||
| ## Syntax |
There was a problem hiding this comment.
most of the items in these two sections seem to be already enforced by rubocop. should we trim the list a bit to what's not covered? mostly to reduce the context and avoid having two sources of truth (which could drift)
| - Refactor bad code instead of explaining it. | ||
| - Avoid superfluous comments (`counter += 1 # Increments counter by one`). | ||
| - Keep comments up to date — an outdated comment is worse than none. | ||
| - Annotations: `TODO`, `FIXME`, `OPTIMIZE`, `HACK`, `REVIEW` + `:` + description, above the relevant code. Document custom annotation keywords in the project README. |
There was a problem hiding this comment.
do we want this? I'd probably just keep TODO. Additional tags can always be added later if they are useful or a convention in the project
| - `Struct.new` for trivial value objects; don't inherit from it. | ||
| - Avoid class variables (`@@var`); prefer class instance variables. | ||
| - Proper visibility (`private`/`protected`); indent modifiers at method level with blank lines. | ||
| - Prefer duck-typing over inheritance. |
There was a problem hiding this comment.
maybe "Prefer composition over inheritance. Use duck typing where appropriate." instead?



Description
This PR improves the Claude Code setup for
rails_api_baseby adding project-specific guidance, agents, commands, rules, and skills focused on Ruby, Rails, RSpec, PR creation, and code review workflows.Changes include:
code-reviewersubagent to review diffs against the base branch using project conventions.pr-size-checkersubagent to detect large PRs and suggest logical splits.create-prcommand to standardize PR creation using the repository template.CLAUDE.mdas the main entry point for Claude Code project context.Notes
This is documentation/tooling only. It does not change application runtime behavior.