Project-specific instructions for AI agents. MUST be loaded at conversation start.
- Architect mode enabled by default: detailed analysis, patterns, trade-offs, architectural guidance
- Stop and ask for context if unable to write code meeting guidelines
Discourse is large with long history. Understand context before changes.
- Always lint changed files
- Create subagent to review changes against this file after completing tasks
- Use
pnpmfor JavaScript,bundlefor Ruby - Use helpers in bin over bundle exec (bin/rspec, bin/rake, bin/lint)
- No empty backing classes for template-only components unless requested
- Use FormKit for forms, see ./docs/developer-guides/docs/03-code-internals/21-form-kit.md (
frontend/discourse/app/form-kit) - Use BEM for CSS, see ./docs/developer-guides/docs/03-code-internals/25-css-guidelines-bem.md
- Make display strings translatable (use placeholders, not split strings)
- Use "Sentence case" for strings, not "Proper Case" or "lower case"
- Do not add JSDoc to any new code you write.
- If JSDoc already exists, ensure any changes you make keep it accurate and up to date.
- Do not write unnecessary comments in tests, every single assertion doesn't need a comment
- Don't test functionality handled by other classes/components
- Don't write obvious tests
- Ruby: use
fab!overlet(), system tests for UI (spec/system), use page objects for system spec finders (spec/system/page_objects)
fab!(:user)- creates object using Fabricator defaults (name matches fabricator)fab!(:user_1, :user)- preferred when variable name differs from fabricator, no custom attributesfab!(:user) { Fabricate(:user, username: "some_username") }- with block for custom attributes
- Located in
spec/system/page_objects/pages/, inherit fromPageObjects::Pages::Base - NEVER store
find()results - causes stale element references after re-renders - Use
has_x?/has_no_x?patterns for state checks (finds fresh each time) - Action methods find+interact atomically, return
selffor chaining - Don't assert immediate UI feedback after clicks (tests browser, not app logic)
To run all RSpec examples in file use bin/rspec <path>. Example:
bin/rspec spec/path/file_spec.rbTo run one or more RSpec examples or groups, append the line number to the path. bin/rspec <path>:<line_number>. Example:
bin/rspec spec/path/file_spec.rb:123# JavaScript tests - bin/qunit
bin/qunit --help # detailed help
bin/qunit path/to/test-file.js # Run all tests in file
bin/qunit path/to/tests/directory # Run all tests in directory# Linting
bin/lint path/to/file path/to/another/file
bin/lint --fix path/to/file path/to/another/file
bin/lint --fix --recent # Lint all recently changed filesALWAYS lint any changes you make
- Configured in
config/site_settings.ymlorconfig/settings.ymlfor plugins - Functionality in
lib/site_setting_extension.rb - Access:
SiteSetting.setting_name(Ruby),siteSettings.setting_name(JS with@service siteSettings)
- Extract business logic (validation, models, permissions) from controllers
- docs/developer-guides/docs/03-code-internals/19-service-objects.md
- Use the skill at .skills/discourse-service-authoring
- Examples:
app/services(only classes withService::Base)
- ActiveRecord: use
includes()/preload()(N+1),find_each()/in_batches()(large sets),update_all/delete_all(bulk),exists?overpresent? - Migrations: rollback logic,
algorithm: :concurrentlyfor large tables, deprecate before removing columns - Use
bin/rails generate migrationfor new migrations - Queries: use
explain, specify columns, strategic indexing,counter_cachefor counts
- 204 No Content: Use
head :no_contentfor successful operations that don't return data- DELETE operations that successfully remove a resource
- UPDATE/PUT operations that succeed but don't need to return modified data
- POST operations that perform an action without creating/returning resources (mark as read, clear notifications)
- 200 OK: Use
render json: success_jsonwhen returning confirmation data or when clients expect a response body - 201 Created: Use when creating resources, include location header or resource data
- Do NOT use 204 when:
- Creating resources (use 201 with data)
- Returning modified/useful data to the client
- Clients expect confirmation data beyond success/failure
- XSS: use
{{}}(escaped) not{{{ }}}, sanitize withsanitize/cook, noinnerHTML, careful with@html - Auth: Guardian classes (
lib/guardian.rb), POST/PUT/DELETE for state changes, CSRF tokens,protect_from_forgery - Input: validate client+server, strong parameters, length limits, don't trust client-only validation
- Authorization: Guardian classes, route+action permissions, scope limiting,
can_see?/can_edit?patterns
- ALWAYS persist information for ALL developers (no conversational-only memory)
- Follow project conventions, prevent knowledge silos
- Recommend storage locations by info type
- Inform when this file changes and reloads