Anatomy of our CLAUDE.md file

5 min read

A good CLAUDE.md (or AGENT.md, AGENTS.md, .cursorrules, etc) file is a huge unlock for our AI colleagues.

After a number of iterations on ours, here's what's been working for us. You can see the entire file in this Gist.

Basic context

First, we situate the agent with basic context by explaining the what and why of the app. Superconductor gives each agent a running instance of our web app, so we let the agent know that the app is already running.

# Superconductor App Development Guide for AI SWE Agents

This is a Rails 8 app, using Tailwind for CSS (with DaisyUI), Slim for HTML templates, Phlex for view components, Stimulus for JavaScript, and Turbo for streaming updates. It runs using docker-compose, which we manage with `dip`.

Read more about the purpose and business logic of the app in @README.md

## Initial Setup (already done)

Before you started, the following two commands were already run for you: `bin/setup` set everything up, and `bin/dev` started the web app.

Useful commands

Next, we explain how to do basic development tasks in our project: add packages, run tests, etc.

We also remind the agent to run an autoformatting script after it's done making changes. With recently shipped Claude Code Hooks, you could skip this part and just run auto formatting automatically.

## Commands useful in development

- `dip bundle add <gem_name>` installs a new Ruby gem.
- `dip pnpm install <package_name>` installs a new JS package. You should aim to use only high-quality gems/packages.
- `dip rails generate migration <MigrationName>` creates a Rails migration file which you can then edit. Consult other migration files for best practices.

Nearly all changes you make, including to CSS, will result in a hot reload of the web app. However, if you make changes in the `config/` directory, then you will need to run `dip overmind restart`, which is the only way to restart the web app.

## Linting and formatting

Human devs have IDEs that autoformat code on every file save. After you edit files, you must do the equivalent by running `dip autoformat`.

This command will also report linter errors that were not automatically fixable. Use your judgement as to which of the linter violations should be fixed.

## Testing

- Non-system tests (fast): `dip test` or `dip test test/<path>.rb`
- System tests (slower): `dip test system` or `dip test system test/system/<path>.rb`
- All of the non-system and system tests (slow): `dip test all`

How to interact with the app

We only use one MCP: Playwright. We've found it to be invaluable for helping Claude make progress on tricky UI tasks. Will be posting about this in the near future.

## Interacting with the app

The only way to interact with our web app is via the browser, at the URL given by `bin/echo-app-url`. Using the browser to test functionality is an important part of your work.

You can use the Playwright MCP to sign in (see `db/seeds/development.rb`), and take screenshots so that you can test the functionality you develop. Use the `browser_take_screenshot`, not the `browser_snapshot` tool.

You should use a subagent for all app interaction tasks.

Debugging

Debugging is like half the job of a software developer, so we explain how to do it. This section would probably benefit from having even more info!

## Debugging

- You can view the web app logs at `log/development.log` (use a subagent to tail at least 200 lines and return the relevant lines)
- If using the Playwright MCP, you can use the `browser_console_messages` tool (use a subagent to return the relevant lines)
- You can run code in the Rails console, either  directly (e.g. `dip rails runner "puts Ticket.count"`) or by first writing out a script file (e.g. `dip rails runner script/print_ticket_count.rb`).

Business logic and important files

We then give the bird's eye view of the business logic and point out several files that are its cornerstones.

We also point out files that are representative of our favorite patterns.

Claude will not read these right away, but it will know what to consult when needed.

By the way, if you do want Claude to read a file right away, you can precede it with @, e.g. @<filename>.

## Patterns

Most AI functionality is in our own library called Agentic, located in `lib/agentic`.
The Agentic library defines a number of Agents, such as `SendMessage` in [send_message.rb](lib/agentic/agents/send_message.rb)
The associated test for `SendMessage` is in [send_message_test.rb](test/lib/agentic/send_message_test.rb)

The Agentic library tries to be app-agnostic, such that it could be used in any Rails app.
Any kind of side effects that are specific to this app are handled by the Adapter pattern.
For example, executing the `SendMessage` creates a `RichMessage` record in the database, which is handled by the `Agentic::Adapters::Ticket::SendMessage` adapter in [send_message.rb](app/lib/agentic/adapters/ticket/send_message.rb)

Some main points of interest for our app business logic:

- [ticket_implementation.rb](app/models/ticket_implementation.rb) defines the `TicketImplementation` model, which has an `AgentOrchestration`
- [agent_orchestration.rb](app/models/agent_orchestration.rb) creates and updates AgentExecutions that track the progress of Agentic agents. It also has a `Conversation`
- [conversation.rb](app/models/conversation.rb) handles the messages which are sent between the user(s) and assistants

Some other representative files that show the best patterns to follow:

- [tickets_controller.rb](app/controllers/admin/tickets_controller.rb) is the main controller for Tickets
- [ticket_query.rb](app/queries/ticket_query.rb) is a query object that defines complex queries on the Ticket model
- [show.html.slim](app/views/tickets/show.html.slim) is the main page for a Ticket
- [conversation_controller.js](app/javascript/controllers/conversation_controller.js) is a Stimulus controller that scrolls to the last message in the conversation

We have our own interface to LLM providers, [llm.rb](lib/llm.rb)

We use concerns for shared behaviors (e.g., `has_public_id`, `agentable`).

We use Font Awesome v6, and new icons must be added to `config/initializers/icons.rb`.

If you have any issues with icon names, first make sure that the name of the icon is a valid v6 name (consult [this list of renamed icons](https://gist.github.com/ve3/3563789a8606c4095847f31522928df6)).

Our coding style preferences and docs

Lastly, we state our preference for less comments and more simply giving things clear names 🙂, and make sure that the agent knows where to find up-to-date docs.

We value code that explains itself through clear class, method, and variable names. Comments may be used when necessary to explain some tricky logic, but should otherwise be avoided.

## Library Docs

- [Ruby on Rails](https://guides.rubyonrails.org/v8.0/index.html)
- [Phlex](https://www.phlex.fun/introduction/)
- [Stimulus](https://stimulus.hotwired.dev/handbook/introduction)
- [Turbo](https://turbo.hotwired.dev/handbook/introduction)
- [Anthropic API](https://docs.anthropic.com/en/docs/overview)
- [OpenAI API](https://platform.openai.com/docs/overview)
- [Gemini API](https://ai.google.dev/gemini-api/docs/)

And that's it. The shorter, the better, as context is still precious.

AI agents now write most of the code of our app http://superconductor.dev. But this is only possible with clear guidance from experienced devs, which starts with CLAUDE.md.

You can see the entire file in this Gist.

Would be curious to see yours!

P.S. We also posted this on X and Reddit.