From 4bfa77789350e0574ee4894983be251d66de723e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Mon, 2 Feb 2026 09:52:35 +0100 Subject: [PATCH] Add Claude Code GitHub Workflow (#17615) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🤖 Installing Claude Code GitHub App This PR adds a GitHub Actions workflow that enables Claude Code integration in our repository. ### What is Claude Code? [Claude Code](https://claude.com/claude-code) is an AI coding agent that can help with: - Bug fixes and improvements - Documentation updates - Implementing new features - Code reviews and suggestions - Writing tests - And more! ### How it works Once this PR is merged, we'll be able to interact with Claude by mentioning @claude in a pull request or issue comment. Once the workflow is triggered, Claude will analyze the comment and surrounding context, and execute on the request in a GitHub action. ### Important Notes - **This workflow won't take effect until this PR is merged** - **@claude mentions won't work until after the merge is complete** - The workflow runs automatically whenever Claude is mentioned in PR or issue comments - Claude gets access to the entire PR or issue context including files, diffs, and previous comments ### Security - Our Anthropic API key is securely stored as a GitHub Actions secret - Only users with write access to the repository can trigger the workflow - All Claude runs are stored in the GitHub Actions run history - Claude's default tools are limited to reading/writing files and interacting with our repo by creating comments, branches, and commits. - We can add more allowed tools by adding them to the workflow file like: ``` allowed_tools: Bash(npm install),Bash(npm run build),Bash(npm run lint),Bash(npm run test) ``` There's more information in the [Claude Code action repo](https://github.com/anthropics/claude-code-action). After merging this PR, let's try mentioning @claude in a comment on any PR to get started! --------- Co-authored-by: Claude Sonnet 4.5 --- .github/workflows/claude.yml | 75 ++++++++++++++++++++++++++++ CLAUDE.md | 96 +++++++++++++++++++++++++----------- 2 files changed, 141 insertions(+), 30 deletions(-) create mode 100644 .github/workflows/claude.yml diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 00000000000..009c48a38cc --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,75 @@ +name: Claude Code + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + pull_request_review: + types: [submitted] + issues: + types: [opened, assigned] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + claude: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + runs-on: ubuntu-latest + timeout-minutes: 60 + permissions: + contents: write + pull-requests: write + issues: write + id-token: write + actions: read + services: + postgres: + image: postgres:16 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + redis: + image: redis + ports: + - 6379:6379 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install dependencies + uses: ./.github/actions/yarn-install + - name: Build shared dependencies + run: | + npx nx build twenty-shared + npx nx build twenty-emails + - name: Setup env files + run: | + npx nx reset:env twenty-front + npx nx reset:env twenty-server + - name: Create databases + run: | + PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";' + PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";' + - name: Run Claude Code + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + additional_permissions: | + actions: read + claude_args: "--max-turns 50" diff --git a/CLAUDE.md b/CLAUDE.md index 3b684f3d854..e4631c43017 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,30 +21,31 @@ npx nx run twenty-server:worker # Start background worker ### Testing ```bash -# Run tests +# Preferred: run a single test file (fast) +npx jest path/to/test.test.ts --config=packages/PROJECT/jest.config.mjs + +# Run all tests for a package npx nx test twenty-front # Frontend unit tests npx nx test twenty-server # Backend unit tests npx nx run twenty-server:test:integration:with-db-reset # Integration tests with DB reset # Storybook -npx nx storybook:build twenty-front # Build Storybook -npx nx storybook:test twenty-front # Run Storybook tests +npx nx storybook:build twenty-front +npx nx storybook:test twenty-front - -When testing the UI end to end, click on "Continue with Email" and use the prefilled credentials. +# When testing the UI end to end, click on "Continue with Email" and use the prefilled credentials. ``` ### Code Quality ```bash -# Linting (diff with main - fastest) -npx nx lint:diff-with-main twenty-front # Lint only files changed vs main -npx nx lint:diff-with-main twenty-server # Lint only files changed vs main -npx nx lint:diff-with-main twenty-front --configuration=fix # Auto-fix files changed vs main +# Linting (diff with main - fastest, always prefer this) +npx nx lint:diff-with-main twenty-front +npx nx lint:diff-with-main twenty-server +npx nx lint:diff-with-main twenty-front --configuration=fix # Auto-fix -# Linting (full project) -npx nx lint twenty-front # Lint all files in frontend -npx nx lint twenty-server # Lint all files in backend -npx nx lint twenty-front --fix # Auto-fix all linting issues +# Linting (full project - slower, use only when needed) +npx nx lint twenty-front +npx nx lint twenty-server # Type checking npx nx typecheck twenty-front @@ -57,7 +58,8 @@ npx nx fmt twenty-server ### Build ```bash -# Build packages +# Build packages (twenty-shared must be built first) +npx nx build twenty-shared npx nx build twenty-front npx nx build twenty-server ``` @@ -69,7 +71,7 @@ npx nx database:reset twenty-server # Reset database npx nx run twenty-server:database:init:prod # Initialize database npx nx run twenty-server:database:migrate:prod # Run migrations -# Generate migration +# Generate migration (replace [name] with kebab-case descriptive name) npx nx run twenty-server:typeorm migration:generate src/database/typeorm/core/migrations/common/[name] -d src/database/typeorm/core/core.datasource.ts # Sync metadata @@ -78,8 +80,9 @@ npx nx run twenty-server:command workspace:sync-metadata ### GraphQL ```bash -# Generate GraphQL types +# Generate GraphQL types (run after schema changes) npx nx run twenty-front:graphql:generate +npx nx run twenty-front:graphql:generate --configuration=metadata ``` ## Architecture Overview @@ -107,13 +110,36 @@ packages/ - **Named exports only** (no default exports) - **Types over interfaces** (except when extending third-party interfaces) - **String literals over enums** (except for GraphQL enums) -- **No 'any' type allowed** +- **No 'any' type allowed** — strict TypeScript enforced - **Event handlers preferred over useEffect** for state updates +- **Props down, events up** — unidirectional data flow +- **Composition over inheritance** +- **No abbreviations** in variable names (`user` not `u`, `fieldMetadata` not `fm`) + +### Naming Conventions +- **Variables/functions**: camelCase +- **Constants**: SCREAMING_SNAKE_CASE +- **Types/Classes**: PascalCase (suffix component props with `Props`, e.g. `ButtonProps`) +- **Files/directories**: kebab-case with descriptive suffixes (`.component.tsx`, `.service.ts`, `.entity.ts`, `.dto.ts`, `.module.ts`) +- **TypeScript generics**: descriptive names (`TData` not `T`) + +### File Structure +- Components under 300 lines, services under 500 lines +- Components in their own directories with tests and stories +- Use `index.ts` barrel exports for clean imports +- Import order: external libraries first, then internal (`@/`), then relative + +### Comments +- Use short-form comments (`//`), not JSDoc blocks +- Explain WHY (business logic), not WHAT +- Do not comment obvious code +- Multi-line comments use multiple `//` lines, not `/** */` ### State Management -- **Recoil** for global state management -- Component-specific state with React hooks +- **Recoil** for global state: atoms for primitive state, selectors for derived state, atom families for dynamic collections +- Component-specific state with React hooks (`useState`, `useReducer` for complex logic) - GraphQL cache managed by Apollo Client +- Use functional state updates: `setState(prev => prev + 1)` ### Backend Architecture - **NestJS modules** for feature organization @@ -122,36 +148,46 @@ packages/ - **Redis** for caching and session management - **BullMQ** for background job processing -### Database +### Database & Migrations - **PostgreSQL** as primary database - **Redis** for caching and sessions -- **TypeORM migrations** for schema management - **ClickHouse** for analytics (when enabled) +- Always generate migrations when changing entity files +- Migration names must be kebab-case (e.g. `add-agent-turn-evaluation`) +- Include both `up` and `down` logic in migrations +- Never delete or rewrite committed migrations + +### Utility Helpers +Use existing helpers from `twenty-shared` instead of manual type guards: +- `isDefined()`, `isNonEmptyString()`, `isNonEmptyArray()` ## Development Workflow IMPORTANT: Use Context7 for code generation, setup or configuration steps, or library/API documentation. Automatically use the Context7 MCP tools to resolve library IDs and get library docs without waiting for explicit requests. ### Before Making Changes -1. Always run linting and type checking after code changes -2. Test changes with relevant test suites -3. Ensure database migrations are properly structured +1. Always run linting (`lint:diff-with-main`) and type checking after code changes +2. Test changes with relevant test suites (prefer single-file test runs) +3. Ensure database migrations are generated for entity changes 4. Check that GraphQL schema changes are backward compatible +5. Run `graphql:generate` after any GraphQL schema changes ### Code Style Notes - Use **Emotion** for styling with styled-components pattern - Follow **Nx** workspace conventions for imports - Use **Lingui** for internationalization -- Components should be in their own directories with tests and stories +- Apply security first, then formatting (sanitize before format) ### Testing Strategy -- **Unit tests** with Jest for both frontend and backend -- **Integration tests** for critical backend workflows -- **Storybook** for component development and testing -- **E2E tests** with Playwright for critical user flows +- **Test behavior, not implementation** — focus on user perspective +- **Test pyramid**: 70% unit, 20% integration, 10% E2E +- Query by user-visible elements (text, roles, labels) over test IDs +- Use `@testing-library/user-event` for realistic interactions +- Descriptive test names: "should [behavior] when [condition]" +- Clear mocks between tests with `jest.clearAllMocks()` ## Important Files - `nx.json` - Nx workspace configuration with task definitions - `tsconfig.base.json` - Base TypeScript configuration - `package.json` - Root package with workspace definitions -- `.cursor/rules/` - Development guidelines and best practices +- `.cursor/rules/` - Detailed development guidelines and best practices