This file provides guidance to Claude Code when working with this repository.
Forest Admin Agent Node.js - SDK for building Forest Admin agents and datasources.
# Core commands
yarn # Install dependencies
yarn build # Build all packages
yarn lint # Lint all packages
yarn lint:fix # Fix lint issues
yarn test # Run all tests
yarn test:coverage # Run tests with coverageCore:
agent- Main Forest Admin agent packageagent-client- RPC client for agent communicationforestadmin-client- Forest Admin API client
Datasources:
datasource-toolkit- Base toolkit for datasourcesdatasource-customizer- Customization layerdatasource-sql- SQL datasourcedatasource-sequelize- Sequelize datasourcedatasource-mongo- MongoDB datasourcedatasource-mongoose- Mongoose datasource
Other:
mcp-server- MCP (Model Context Protocol) server for AI integrationai-proxy- AI/LLM integration proxyforest-cloud- Cloud deployment utilitiesplugin-*- Various plugins (aws-s3, export-advanced, flattener)
Node.js | TypeScript | Jest | Lerna | ESM
ESLint (Airbnb TypeScript) | Prettier | Conventional Commits | Semantic release
Use Jest for all tests. Run package-specific tests with workspace commands:
yarn workspace @forestadmin/mcp-server test
yarn workspace @forestadmin/agent test- Assertions must verify behavior - Don't just check that a function was called; verify it was called with the correct arguments
- Test name = assertion - If the test says "selects config X", the assertion must verify config X was selected
- Avoid weak assertions:
- ❌
expect(mock).toHaveBeenCalled()- only checks the function was called - ✅
expect(mock).toHaveBeenCalledWith({ host: 'localhost', port: 3000 })- verifies exact arguments - ✅
expect(mock).toHaveBeenCalledWith(expect.objectContaining({ host: 'localhost' }))- partial match when some values are dynamic
- ❌
- One behavior per test - Each test should verify one specific behavior
- Use AAA pattern - Arrange (setup), Act (execute), Assert (verify) - keep these sections clear
- Test edge cases - Not just happy paths; test errors, null values, empty arrays, boundaries
- Test behavior, not implementation - Assert on observable outputs, not internal method calls
- Coverage ≠ quality - 100% coverage with weak assertions is worse than 80% with strong assertions
- DRY (Don't Repeat Yourself) - Extract common logic into reusable functions/services
- KISS (Keep It Simple, Stupid) - Prefer simple, readable solutions over clever ones
- YAGNI (You Aren't Gonna Need It) - Don't implement features "just in case"
- Single Responsibility - One function = one task
- Size - Keep functions short (20-30 lines max); split if longer
- Naming - Descriptive names that explain what, not how (
getUserPermissionsnotgetData) - Parameters - Max 3-4 parameters; use an options object for more
- Return early - Guard clauses at the top, avoid deep nesting
- No magic numbers/strings - Use named constants
- Avoid side effects - Pure functions when possible
- Handle errors explicitly - No silent failures
- Comments - Explain why, not what (code should be self-documenting)
- Does this code do one thing well?
- Can I understand it in 30 seconds?
- Is there duplication that should be extracted?
- Are there unused variables/imports?
- Are edge cases handled?
- Is the naming clear and consistent?
If the Linear MCP server is not installed, add it to your Claude Code configuration:
claude mcp add linear-server npx -- -y @anthropic/linear-mcp-serverWhen pushing a PR that relates to an existing Linear ticket:
-
Include the issue identifier in the branch name
- Example:
fix/prd-139-list-not-refreshing - Linear automatically detects PRs from branches containing
PRD-XXX
- Example:
-
Add the Linear ticket ID prefixed with "fixes" in the PR body
- Example:
fixes PRD-139 - This creates the GitHub → Linear link
- Example:
Use mcp__linear-server__create_issue to create tickets:
title: "Bug title"
description: "## Description\n\n..."
team: "Product"
labels: ["bug"] # optionalTeam: Product for product-related issues
Labels (optional, skip for small tasks):
bug- Bug reportsepic- Large feature groupingssub epic- Smaller parts of epics
The response includes a gitBranchName field with a suggested branch name containing the issue identifier.