

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
1# CLAUDE.md23This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.45## Common Development Commands67### Development Server8- `bin/dev` - Start development server (Rails, Sidekiq, Tailwind CSS watcher)9- `bin/rails server` - Start Rails server only10- `bin/rails console` - Open Rails console1112### Testing13- `bin/rails test` - Run all tests14- `bin/rails test:db` - Run tests with database reset15- `DISABLE_PARALLELIZATION=true bin/rails test:system` - Run system tests only (use sparingly - they take longer)16- `bin/rails test test/models/account_test.rb` - Run specific test file17- `bin/rails test test/models/account_test.rb:42` - Run specific test at line1819#### System Tests in the Dev Container20When running inside the Dev Container, the `SELENIUM_REMOTE_URL` environment variable is automatically set to the bundled `selenium/standalone-chromium` service. System tests will connect to that remote browser — no local Chrome installation is required.2122```bash23DISABLE_PARALLELIZATION=true bin/rails test:system24```2526To watch the browser live, open `http://localhost:7900` or `http://localhost:4444` in your host browser (password: `secret`).2728### Linting & Formatting29- `bin/rubocop` - Run Ruby linter30- `npm run lint` - Check JavaScript/TypeScript code31- `npm run lint:fix` - Fix JavaScript/TypeScript issues32- `npm run format` - Format JavaScript/TypeScript code33- `bin/brakeman` - Run security analysis3435### Database36- `bin/rails db:prepare` - Create and migrate database37- `bin/rails db:migrate` - Run pending migrations38- `bin/rails db:rollback` - Rollback last migration39- `bin/rails db:seed` - Load seed data4041### Setup42- `bin/setup` - Initial project setup (installs dependencies, prepares database)4344## Pre-Pull Request CI Workflow4546ALWAYS run these commands before opening a pull request:47481. **Tests** (Required):49 - `bin/rails test` - Run all tests (always required)50 - `DISABLE_PARALLELIZATION=true bin/rails test:system` - Run system tests (only when applicable, they take longer)51522. **Linting** (Required):53 - `bin/rubocop -f github -a` - Ruby linting with auto-correct54 - `bundle exec erb_lint ./app/**/*.erb -a` - ERB linting with auto-correct55563. **Security** (Required):57 - `bin/brakeman --no-pager` - Security analysis5859Only proceed with pull request creation if ALL checks pass.6061## General Development Rules6263### Authentication Context64- Use `Current.user` for the current user. Do NOT use `current_user`.65- Use `Current.family` for the current family. Do NOT use `current_family`.6667### Development Guidelines68- Carefully read project conventions and guidelines before generating any code.69- Do not run `rails server` in your responses70- Do not run `touch tmp/restart.txt`71- Do not run `rails credentials`72- Do not automatically run migrations7374## High-Level Architecture7576### Application Modes77The codebase runs in two distinct modes:78- **Managed**: A team operates and manages servers for users (Rails.application.config.app_mode = "managed")79- **Self Hosted**: Users host the codebase on their own infrastructure, typically through Docker Compose (Rails.application.config.app_mode = "self_hosted")8081### Core Domain Model82The application is built around financial data management with these key relationships:83- **User** → has many **Accounts** → has many **Transactions**84- **Account** types: checking, savings, credit cards, investments, crypto, loans, properties85- **Transaction** → belongs to **Category**, can have **Tags** and **Rules**86- **Investment accounts** → have **Holdings** → track **Securities** via **Trades**8788### API Architecture89The application provides both internal and external APIs:90- Internal API: Controllers serve JSON via Turbo for SPA-like interactions91- External API: `/api/v1/` namespace with Doorkeeper OAuth and API key authentication92- API responses use Jbuilder templates for JSON rendering93- Rate limiting via Rack Attack with configurable limits per API key94- **OpenAPI Documentation**: All API endpoints MUST have corresponding OpenAPI specs in `spec/requests/api/` using rswag. See `docs/api/openapi.yaml` for the generated documentation.9596### Sync & Import System97Two primary data ingestion methods:981. **Plaid Integration**: Real-time bank account syncing99 - `PlaidItem` manages connections100 - `Sync` tracks sync operations101 - Background jobs handle data updates1022. **CSV Import**: Manual data import with mapping103 - `Import` manages import sessions104 - Supports transaction and balance imports105 - Custom field mapping with transformation rules106107### Provider Integrations: Pending Transactions and FX (SimpleFIN/Plaid)108109- Detection110 - SimpleFIN: pending via `pending: true` or `posted` blank/0 + `transacted_at`.111 - Plaid: pending via Plaid `pending: true` (stored at `extra["plaid"]["pending"]` for bank/credit transactions imported via `PlaidEntry::Processor`).112- Storage: provider data on `Transaction#extra` (e.g., `extra["simplefin"]["pending"]`; FX uses `fx_from`, `fx_date`).113- UI: "Pending" badge when `transaction.pending?` is true; no badge if provider omits pendings.114- Configuration (default-on for pending)115 - SimpleFIN: `config/initializers/simplefin.rb` via `Rails.configuration.x.simplefin.*`.116 - Plaid: `config/initializers/plaid_config.rb` via `Rails.configuration.x.plaid.*`.117 - Pending transactions are fetched by default and handled via reconciliation/filtering.118 - Set `SIMPLEFIN_INCLUDE_PENDING=0` to disable pending fetching for SimpleFIN.119 - Set `PLAID_INCLUDE_PENDING=0` to disable pending fetching for Plaid.120 - Set `SIMPLEFIN_DEBUG_RAW=1` to enable raw payload debug logging.121 - Set `UP_DEBUG_RAW=1` to enable raw Up payload debug logging. DEV-ONLY: the dump contains PII and is gated to local environments, so it never logs in managed/production.122123Provider support notes:124- SimpleFIN: supports pending + FX metadata (stored under `extra["simplefin"]`).125- Plaid: supports pending when the upstream Plaid payload includes `pending: true` (stored under `extra["plaid"]`).126- Plaid investments: investment transactions currently do not store pending metadata.127- Lunchflow: does not currently store pending metadata.128129### Background Processing130Sidekiq handles asynchronous tasks:131- Account syncing (`SyncJob`)132- Import processing (`ImportJob`)133- AI chat responses (`AssistantResponseJob`)134- Scheduled maintenance via sidekiq-cron135136### Debug Logging for Provider Syncs137- Prefer `DebugLogEntry.capture(...)` over `Rails.logger.*` for provider sync/import failures, partial responses, and other support-relevant diagnostics.138- Record support-relevant incidents in the super-admin `/settings/debug` UI rather than leaving them only in raw application logs.139- Include `category`, `level`, `message`, `source`, `provider_key`, and structured `metadata`.140- Attach `family` and `account_provider` whenever possible so support can filter to the affected provider connection.141142### Frontend Architecture143- **Hotwire Stack**: Turbo + Stimulus for reactive UI without heavy JavaScript144- **ViewComponents**: Reusable UI components in `app/components/`145- **Stimulus Controllers**: Handle interactivity, organized alongside components146- **Charts**: D3.js for financial visualizations (time series, donut, sankey)147- **Styling**: Tailwind CSS v4.x with custom design system148 - Design system defined in `app/assets/tailwind/sure-design-system.css`149 - Always use functional tokens (e.g., `text-primary` not `text-white`)150 - Prefer semantic HTML elements over JS components151 - Use `icon` helper for icons, never `lucide_icon` directly152- **i18n**: All user-facing strings must use localization (i18n). Update locale files for each new or changed element.153154### Internationalization (i18n) Guidelines155- **Key Organization**: Use hierarchical keys by feature: `accounts.index.title`, `transactions.form.amount_label`156- **Translation Helper**: Always use `t()` helper for user-facing strings157- **Interpolation**: Use for dynamic content: `t("users.greeting", name: user.name)`158- **Pluralization**: Use Rails pluralization: `t("transactions.count", count: @transactions.count)`159- **Locale Files**: Update `config/locales/en.yml` for new strings160- **Missing Translations**: Configure to raise errors in development for missing keys161162### Multi-Currency Support163- All monetary values stored in base currency (user's primary currency)164- `Money` objects handle currency conversion and formatting165- Historical exchange rates for accurate reporting166167### Security & Authentication168- Session-based auth for web users169- API authentication via:170 - OAuth2 (Doorkeeper) for third-party apps171 - API keys with JWT tokens for direct API access172- Scoped permissions system for API access173- Strong parameters and CSRF protection throughout174175### Testing Philosophy176- Comprehensive test coverage using Rails' built-in Minitest177- Fixtures for test data (avoid FactoryBot)178- Keep fixtures minimal (2-3 per model for base cases)179- VCR for external API testing180- System tests for critical user flows (use sparingly)181- Test helpers in `test/support/` for common scenarios182- Only test critical code paths that significantly increase confidence183- Write tests as you go, when required184- **API Endpoints require OpenAPI specs** in `spec/requests/api/` for documentation purposes ONLY, not test (uses RSpec + rswag)185186### Performance Considerations187- Database queries optimized with proper indexes188- N+1 queries prevented via includes/joins189- Background jobs for heavy operations190- Caching strategies for expensive calculations191- Turbo Frames for partial page updates192193### Development Workflow194- Feature branches merged to `main`195- Docker support for consistent environments196- Environment variables via `.env` files197- Lookbook for component development (`/lookbook`)198- Letter Opener for email preview in development199200## Project Conventions201202### Convention 1: Minimize Dependencies203- Push Rails to its limits before adding new dependencies204- Strong technical/business reason required for new dependencies205- Favor old and reliable over new and flashy206207### Convention 2: Skinny Controllers, Fat Models208- Business logic in `app/models/` folder, avoid `app/services/`209- Use Rails concerns and POROs for organization210- Models should answer questions about themselves: `account.balance_series` not `AccountSeries.new(account).call`211212### Convention 3: Hotwire-First Frontend213- **Native HTML preferred over JS components**214 - Use `<dialog>` for modals, `<details><summary>` for disclosures215- **Leverage Turbo frames** for page sections over client-side solutions216- **Query params for state** over localStorage/sessions217- **Server-side formatting** for currencies, numbers, dates218- **Always use `icon` helper** in `application_helper.rb`, NEVER `lucide_icon` directly219220### Convention 4: Optimize for Simplicity221- Prioritize good OOP domain design over performance222- Focus performance only on critical/global areas (avoid N+1 queries, mindful of global layouts)223224### Convention 5: Database vs ActiveRecord Validations225- Simple validations (null checks, unique indexes) in DB226- ActiveRecord validations for convenience in forms (prefer client-side when possible)227- Complex validations and business logic in ActiveRecord228229## TailwindCSS Design System230231### Design System Rules232- **Always reference `app/assets/tailwind/sure-design-system.css`** for primitives and tokens233- **Use functional tokens** defined in design system:234 - `text-primary` instead of `text-white`235 - `bg-container` instead of `bg-white`236 - `border border-primary` instead of `border border-gray-200`237- **NEVER create new styles** in design system files without permission238- **Always generate semantic HTML**239240## Component Architecture241242### ViewComponent vs Partials Decision Making243244**Use ViewComponents when:**245- Element has complex logic or styling patterns246- Element will be reused across multiple views/contexts247- Element needs structured styling with variants/sizes248- Element requires interactive behavior or Stimulus controllers249- Element has configurable slots or complex APIs250- Element needs accessibility features or ARIA support251252**Use Partials when:**253- Element is primarily static HTML with minimal logic254- Element is used in only one or few specific contexts255- Element is simple template content256- Element doesn't need variants, sizes, or complex configuration257- Element is more about content organization than reusable functionality258259**Component Guidelines:**260- Prefer components over partials when available261- Keep domain logic OUT of view templates262- Logic belongs in component files, not template files263264### Stimulus Controller Guidelines265266**Declarative Actions (Required):**267```erb268<!-- GOOD: Declarative - HTML declares what happens -->269<div data-controller="toggle">270 <button data-action="click->toggle#toggle" data-toggle-target="button">271 <%= t("components.transaction_details.show_details") %>272 </button>273 <div data-toggle-target="content" class="hidden">274 <p><%= t("components.transaction_details.amount_label") %>: <%= @transaction.amount %></p>275 <p><%= t("components.transaction_details.date_label") %>: <%= @transaction.date %></p>276 <p><%= t("components.transaction_details.category_label") %>: <%= @transaction.category.name %></p>277 </div>278</div>279```280281**Example locale file structure (config/locales/en.yml):**282```yaml283en:284 components:285 transaction_details:286 show_details: "Show Details"287 hide_details: "Hide Details"288 amount_label: "Amount"289 date_label: "Date"290 category_label: "Category"291```292293**i18n Best Practices:**294- Organize keys by feature/component: `components.transaction_details.show_details`295- Use descriptive key names that indicate purpose: `show_details` not `button`296- Group related translations together in the same namespace297- Use interpolation for dynamic content: `t("users.welcome", name: user.name)`298- Always update locale files when adding new user-facing strings299300**Controller Best Practices:**301- Keep controllers lightweight and simple (< 7 targets)302- Use private methods and expose clear public API303- Single responsibility or highly related responsibilities304- Component controllers stay in component directory, global controllers in `app/javascript/controllers/`305- Pass data via `data-*-value` attributes, not inline JavaScript306307## Testing Philosophy308309### General Testing Rules310- **ALWAYS use Minitest + fixtures** (NEVER RSpec or factories)311- Keep fixtures minimal (2-3 per model for base cases)312- Create edge cases on-the-fly within test context313- Use Rails helpers for large fixture creation needs314315### Test Quality Guidelines316- **Write minimal, effective tests** - system tests sparingly317- **Only test critical and important code paths**318- **Test boundaries correctly:**319 - Commands: test they were called with correct params320 - Queries: test output321 - Don't test implementation details of other classes322323### Testing Examples324325```ruby326# GOOD - Testing critical domain business logic327test "syncs balances" do328 Holding::Syncer.any_instance.expects(:sync_holdings).returns([]).once329 assert_difference "@account.balances.count", 2 do330 Balance::Syncer.new(@account, strategy: :forward).sync_balances331 end332end333334# BAD - Testing ActiveRecord functionality335test "saves balance" do336 balance_record = Balance.new(balance: 100, currency: "USD")337 assert balance_record.save338end339```340341### Stubs and Mocks342- Use `mocha` gem343- Prefer `OpenStruct` for mock instances344- Only mock what's necessary345346## API Development Guidelines347348### OpenAPI Documentation (MANDATORY)349When adding or modifying API endpoints in `app/controllers/api/v1/`, you **MUST** create or update corresponding OpenAPI request specs:3503511. **Location**: `spec/requests/api/v1/{resource}_spec.rb`3522. **Framework**: RSpec with rswag for OpenAPI generation3533. **Schemas**: Define reusable schemas in `spec/swagger_helper.rb`3544. **Generated Docs**: `docs/api/openapi.yaml`355356**Example structure for a new API endpoint:**357```ruby358# spec/requests/api/v1/widgets_spec.rb359require 'swagger_helper'360361RSpec.describe 'API V1 Widgets', type: :request do362 path '/api/v1/widgets' do363 get 'List widgets' do364 tags 'Widgets'365 security [ { apiKeyAuth: [] } ]366 produces 'application/json'367368 response '200', 'widgets listed' do369 schema '$ref' => '#/components/schemas/WidgetCollection'370 run_test!371 end372 end373 end374end375```376377**Regenerate OpenAPI docs after changes:**378```bash379RAILS_ENV=test bundle exec rake rswag:specs:swaggerize380```381382### Post-commit API consistency (issue #944)383After every API endpoint commit, ensure:3843851. **Minitest behavioral coverage** — Add or update tests in `test/controllers/api/v1/{resource}_controller_test.rb`. Use API key and `api_headers` (X-Api-Key). Cover index/show, CRUD where relevant, 401/403/422/404. Do not rely on rswag for behavioral assertions.3863872. **rswag docs-only** — Do not add `expect(...)` or `assert_*` in `spec/requests/api/v1/`. Use `run_test!` only so specs document request/response and regenerate `docs/api/openapi.yaml`.3883893. **Same API key auth in rswag** — Every request spec in `spec/requests/api/v1/` must use the same API key pattern (`ApiKey.generate_secure_key`, `ApiKey.create!(...)`, `let(:'X-Api-Key') { api_key.plain_key }`). Do not use Doorkeeper/OAuth in those specs so generated docs stay consistent.390391Full checklist and pattern: [.cursor/rules/api-endpoint-consistency.mdc](.cursor/rules/api-endpoint-consistency.mdc).392393To verify the implementation: `ruby test/support/verify_api_endpoint_consistency.rb`. To scan the current APIs for violations: `ruby test/support/verify_api_endpoint_consistency.rb --compliance`.
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| we-promise/sure.cursor/rules/api-endpoint-consistency.mdc · 9.5k | Cursor rules | styletesting-strategygitsecurity+2 | 57/100 | 13 days ago | |
| we-promise/sure.cursor/rules/cursor_rules.mdc · 9.5k | Cursor rules | no sections | 36/100 | 13 days ago | |
| we-promise/sure.cursor/rules/general-rules.mdc · 9.5k | Cursor rules | styledo-not | 44/100 | 13 days ago | |
| we-promise/sure.cursor/rules/project-conventions.mdc · 9.5k | Cursor rules | styledependenciesdatabaseui+2 | 59/100 | 13 days ago | |
| we-promise/sure.cursor/rules/project-design.mdc · 9.5k | Cursor rules | style | 58/100 | 13 days ago | |
| we-promise/sure.cursor/rules/self_improve.mdc · 9.5k | Cursor rules | no sections | 36/100 | 13 days ago | |
| we-promise/sure.cursor/rules/stimulus_conventions.mdc · 9.5k | Cursor rules | no sections | 44/100 | 13 days ago | |
| we-promise/sure.cursor/rules/testing.mdc · 9.5k | Cursor rules | styletesting-strategy | 52/100 | 13 days ago | |
| we-promise/sure.cursor/rules/ui-ux-design-guidelines.mdc · 9.5k | Cursor rules | styledo-not | 49/100 | 13 days ago | |
| we-promise/sure.cursor/rules/view_conventions.mdc · 9.5k | Cursor rules | style | 52/100 | 13 days ago | |
| we-promise/sure.github/copilot-instructions.md · 9.5k | Copilot instructions | setuptestlint-formatstyle+10 | 88/100 | 13 days ago | |
| we-promise/sureAGENTS.md · 9.5k | AGENTS.md | buildtestlint-formatstyle+7 | 78/100 | 13 days ago |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| tyrchen/geektime-bootcamp-aiw7/genslides/backend/CLAUDE.md · 230 | CLAUDE.md | testlint-formatstylearch+6 | 100/100 | 9 days ago | |
| khrnchn/sedekah-jeCLAUDE.md · 89 | CLAUDE.md | testlint-formatstylearch+6 | 97/100 | 14 days ago | |
| oven-sh/buntest/CLAUDE.md · 95k | CLAUDE.md | teststyletesting-strategydo-not | 97/100 | 14 days ago | |
| oven-sh/bunCLAUDE.md · 95k | CLAUDE.md | buildteststylearch+3 | 96/100 | 14 days ago | |
| settlemint/sdkCLAUDE.md · 15 | CLAUDE.md | setupbuildtestlint-format+10 | 96/100 | 14 days ago | |
| wodsmith/thewodappCLAUDE.md · 2 | CLAUDE.md | buildtestlint-formatstyle+7 | 96/100 | 14 days ago | |
| yigitkonur/cli-continuesCLAUDE.md · 1.4k | CLAUDE.md | setupbuildteststyle+4 | 94/100 | 14 days ago | |
| akodkod/operandiCLAUDE.md · 73 | CLAUDE.md | buildteststyletesting-strategy+4 | 93/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/we-promise-sure-claude)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.