Development Workflow Guide
Development Workflow Guide
Separation of Duties: See Separation of Duties - Development workflow documentation is responsible for development patterns and workflows. It does NOT own agent manifests, execution, or infrastructure configuration.
Consolidated development patterns for TypeScript/JavaScript projects in the LLM Platform ecosystem.
Table of Contents
- NPM Scripts
- Pre-commit Hooks (Lefthook)
- TypeScript Configuration
- ESLint and Prettier Setup
- Git Workflow with Worktrees
- Environment Setup
NPM Scripts
Standard Script Patterns
All packages in the ecosystem follow consistent npm script patterns:
Core Scripts (Required)
{ "scripts": { "build": "tsc", "dev": "next dev", "start": "next start", "test": "jest", "lint": "eslint src/", "typecheck": "tsc --noEmit" } }
Testing Scripts
{ "scripts": { "test": "jest", "test:e2e": "playwright test", "test:e2e:ui": "playwright test --ui", "test:e2e:debug": "playwright test --debug", "test:e2e:report": "playwright show-report", "test:php": "phpunit", "test:drupal": "drush test-run --verbose", "test:integration": "jest --testPathPattern=integration", "test:coverage": "jest --coverage", "install:playwright": "playwright install" } }
OpenAPI Scripts
{ "scripts": { "generate:types": "node scripts/generate-types.cjs openapi.yaml src/generated", "generate:types:clean": "rm -rf src/generated", "openapi:validate": "npx @redocly/cli lint openapi.yaml", "openapi:bundle": "npx @redocly/cli bundle openapi.yaml -o openapi.json", "openapi:html": "npx redoc-cli bundle openapi.yaml -o openapi.html" } }
Standard Dependencies
Runtime Dependencies
{ "dependencies": { "commander": "^11.0.0", "chalk": "^5.3.0", "zod": "^3.22.4" } }
Development Dependencies
{ "devDependencies": { "@playwright/test": "^1.54.2", "@types/node": "^20.0.0", "typescript": "^5.0.0", "eslint": "^8.57.0", "prettier": "^3.0.0", "axe-playwright": "^2.0.3" } }
Frontend (Next.js) Dependencies
{ "dependencies": { "@radix-ui/react-slot": "^1.0.2", "@tanstack/react-query": "^5.0.0", "axios": "^1.7.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "lucide-react": "^0.403.0", "next": "15.5.3", "react": "^18.2.0", "react-dom": "^18.2.0", "recharts": "^2.8.0", "tailwind-merge": "^2.3.0", "zod": "^3.23.8" }, "devDependencies": { "@types/react": "^18.3.1", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.19", "eslint-config-next": "14.2.3", "postcss": "^8.4.38", "tailwindcss": "^3.4.3" } }
Pre-commit Hooks (Lefthook)
Standard Lefthook Configuration
All projects use Lefthook for Git hooks. Create lefthook.yml in project root:
# lefthook.yml - Standard Configuration pre-commit: parallel: true commands: # Block markdown files in root (use GitLab Wiki) block-root-md: run: | ROOT_MD=$(git diff --cached --name-only --diff-filter=A | grep -E '^[^/]+.md$' | grep -v '^README.md$' | grep -v '^CHANGELOG.md$' | grep -v '^TESTING.md$' || true) if [ -n "$ROOT_MD" ]; then echo "ERROR: .md files in root are forbidden" echo "$ROOT_MD" | sed 's/^/ - /' echo "Use GitLab Wiki instead: buildkit gitlab wiki create --slug \"page-name\" --file file.md" echo "(Exception: README.md, CHANGELOG.md, TESTING.md required for Drupal.org)" exit 1 fi files: git diff --cached --name-only --diff-filter=A glob: '*.md' # Block shell scripts (use BuildKit CLI) block-sh-scripts: run: | SH_FILES=$(git diff --cached --name-only --diff-filter=A | grep '\.sh$' || true) if [ -n "$SH_FILES" ]; then echo "ERROR: .sh scripts are FORBIDDEN (use agent-buildkit CLI)" echo "$SH_FILES" | sed 's/^/ - /' exit 1 fi files: git diff --cached --name-only --diff-filter=A glob: '*.sh' # Format code format: run: | if [ -f "package.json" ] && command -v npm >/dev/null 2>&1; then if npm run format >/dev/null 2>&1; then npm run format fi fi root: . stage_fixed: true skip: - merge - rebase # Lint code lint: run: | if [ -f "package.json" ] && command -v npm >/dev/null 2>&1; then if npm run lint >/dev/null 2>&1; then npm run lint fi fi root: . files: git diff --cached --name-only --diff-filter=ACM skip: - merge - rebase # TypeScript type checking typecheck: run: | if [ -f "package.json" ] && command -v npm >/dev/null 2>&1; then if npm run typecheck >/dev/null 2>&1; then npm run typecheck fi fi root: . glob: '**/*.{ts,tsx}' skip: - merge - rebase # PHP CodeSniffer (Drupal modules) phpcs: glob: '**/*.{php,module,install,theme,inc}' root: . run: | if [ -f "composer.json" ] && command -v composer >/dev/null 2>&1; then if composer run-script --list 2>/dev/null | grep -q "phpcs"; then composer phpcs fi fi skip: - merge - rebase # PHPStan (Drupal modules) phpstan: glob: '**/*.{php,module,install,theme,inc}' root: . run: | if [ -f "composer.json" ] && command -v composer >/dev/null 2>&1; then if composer run-script --list 2>/dev/null | grep -q "phpstan"; then composer phpstan fi fi skip: - merge - rebase commit-msg: commands: # Block AI attribution in commits claude-protection: run: | COMMIT_MSG_FILE="{1}" if [ -z "$COMMIT_MSG_FILE" ] || [ "$COMMIT_MSG_FILE" = "{1}" ]; then COMMIT_MSG_FILE=".git/COMMIT_EDITMSG" fi if [ ! -f "$COMMIT_MSG_FILE" ]; then exit 0 fi COMMIT_MSG=$(cat "$COMMIT_MSG_FILE") if echo "$COMMIT_MSG" | grep -qiE "Generated with.*Claude|Co-Authored-By:.*Claude|claude.ai|noreply@anthropic.com"; then echo "COMMIT BLOCKED: Forbidden Claude/AI attribution detected!" echo " Write as the human developer" echo " Use professional technical language" exit 1 fi # Require issue reference for feature branches require-issue-ref: run: | BRANCH=$(git branch --show-current) if [[ "$BRANCH" =~ ^(feature|bug|hotfix|chore) ]] && ! grep -qiE "(#[0-9]+|issue|gitlab)" "$1"; then echo "WARNING: Branch '$BRANCH' should reference GitLab Issue" echo " Format: 'feat: description (fixes #123)'" fi pre-push: commands: # Run tests before push test: run: | if [ -f "package.json" ] && command -v npm >/dev/null 2>&1; then if npm test >/dev/null 2>&1; then npm test fi elif [ -f "composer.json" ] && command -v composer >/dev/null 2>&1; then if composer run-script --list 2>/dev/null | grep -q "test"; then composer test fi fi root: . skip: - merge - rebase # Security audit security-audit: run: | if [ -f "package.json" ] && command -v npm >/dev/null 2>&1; then npm audit --audit-level=moderate || true fi root: . skip: - merge - rebase # Block pushes to development branch from Claude Code block-claude-on-development: run: | BRANCH=$(git branch --show-current) if [ "$BRANCH" = "development" ]; then echo "BLOCKED: Claude Code not allowed on development branch" echo "Use feature branches only" exit 1 fi skip_output: - meta - summary
Installing Lefthook
# Install lefthook npm install -D lefthook # Initialize hooks npx lefthook install
TypeScript Configuration
Standard tsconfig.json
{ "compilerOptions": { "target": "ES2022", "module": "ES2022", "moduleResolution": "Node", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "declaration": true, "declarationMap": true, "sourceMap": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "tests"] }
Next.js tsconfig.json
{ "compilerOptions": { "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "plugins": [ { "name": "next" } ], "paths": { "@/*": ["./src/*"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"] }
ESLint and Prettier Setup
ESLint Configuration (.eslintrc.js)
module.exports = { parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint'], parserOptions: { ecmaVersion: 2022, sourceType: 'module' }, env: { node: true, es2022: true }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended' ], rules: { // Recommended rules for production 'no-console': 'warn', '@typescript-eslint/no-explicit-any': 'warn', '@typescript-eslint/explicit-function-return-type': 'off', 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }] } };
ESLint Relaxed Configuration (for cleanup work)
// .eslintrc.relaxed.js module.exports = { parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint'], parserOptions: { ecmaVersion: 2022, sourceType: 'module' }, env: { node: true, es2022: true }, rules: { // Relaxed rules for cleanup/refactoring work 'no-console': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/explicit-function-return-type': 'off', 'max-lines': 'off', 'max-lines-per-function': 'off', 'complexity': 'off', 'no-magic-numbers': 'off' } };
Prettier Configuration (.prettierrc.json)
{ "printWidth": 80, "tabWidth": 2, "useTabs": false, "semi": true, "singleQuote": true, "quoteProps": "as-needed", "jsxSingleQuote": false, "trailingComma": "es5", "bracketSpacing": true, "bracketSameLine": false, "arrowParens": "always", "requirePragma": false, "insertPragma": false, "proseWrap": "preserve", "htmlWhitespaceSensitivity": "css", "vueIndentScriptAndStyle": false, "endOfLine": "lf", "embeddedLanguageFormatting": "auto", "singleAttributePerLine": false, "overrides": [ { "files": "*.md", "options": { "proseWrap": "always" } }, { "files": "*.json", "options": { "tabWidth": 2 } }, { "files": "*.yml", "options": { "tabWidth": 2 } } ] }
.prettierignore
node_modules/
dist/
build/
.next/
coverage/
*.min.js
*.min.css
Git Workflow with Worktrees
Overview
All development work happens in Git worktrees, not in the main repository directory. This ensures:
- Main project directories always stay on
developmentbranch - Feature work happens in isolation
- No branch switching disrupts other work
- Multiple features can be developed in parallel
Worktree Directory Structure
~/Sites/LLM/ # Main repositories (stay on development)
~/Sites/.workingtrees/LLM/ # All worktrees (CANONICAL location)
agent-buildkit/
feature-123-auth/
platform-agents/
bugfix-456-fix/
llm-platform/
chore-789-cleanup/
Complete Workflow
1. Create Issue in GitLab
# Browse to GitLab or use CLI glab issue create --title "Feature: Add user authentication"
2. Create MR from Issue Page
On the GitLab issue page, click "Create merge request" button. GitLab will:
- Create the branch automatically:
{issue#}-{title-slug} - Link MR to issue
- Set MR to auto-close issue when merged
3. Fetch and Create Worktree
# Fetch the new branch cd ~/Sites/LLM/<project> git fetch origin # Create worktree for the branch git worktree add ~/Sites/.workingtrees/LLM/<project>/<branch> origin/<branch> # Navigate to worktree cd ~/Sites/.workingtrees/LLM/<project>/<branch>
4. Make Changes and Commit
# Work in worktree cd ~/Sites/.workingtrees/LLM/<project>/<branch> # Make changes npm install npm run build npm test # Commit with conventional format git add . git commit -m "feat(auth): implement user authentication (fixes #123)" git push
5. After MR Merges
# Return to main project cd ~/Sites/LLM/<project> # Remove worktree git worktree remove ~/Sites/.workingtrees/LLM/<project>/<branch> # Delete local branch git branch -d <branch> # Update main git pull origin development
Quick Commands Reference
# Create worktree git worktree add ~/Sites/.workingtrees/LLM/<project>/<branch> origin/<branch> # List worktrees git worktree list # Remove worktree git worktree remove ~/Sites/.workingtrees/LLM/<project>/<branch> # Prune stale worktrees git worktree prune
One-liner: Setup New Feature
git fetch origin && \ git worktree add ~/Sites/.workingtrees/LLM/<project>/<branch> origin/<branch> && \ cd ~/Sites/.workingtrees/LLM/<project>/<branch>
One-liner: Cleanup After Merge
cd ~/Sites/LLM/<project> && \ git worktree remove ~/Sites/.workingtrees/LLM/<project>/<branch> && \ git pull origin development
Critical Rules
| Rule | Description |
|---|---|
| NEVER create branches manually | Use GitLab "Create merge request" from issue |
| ALWAYS use worktrees | Never checkout branches in main repo |
| Main projects stay on development | ~/Sites/LLM/* directories never change branches |
| Reference issues in commits | Format: type(scope): description (fixes #123) |
Environment Setup
Prerequisites
# Install Node.js 20+ nvm install 20 nvm use 20 # Verify versions node --version # Should be 20.x+ npm --version # Should be 10.x+
Token Management
All tokens stored in ~/.tokens/:
# Create tokens directory mkdir -p ~/.tokens chmod 700 ~/.tokens # Store API keys echo "your-key" > ~/.tokens/anthropic echo "your-key" > ~/.tokens/openai echo "your-key" > ~/.tokens/gitlab chmod 600 ~/.tokens/*
Environment Variables
# Node options export NODE_OPTIONS="--max-old-space-size=4096" # Load tokens export ANTHROPIC_API_KEY=$(cat ~/.tokens/anthropic) export OPENAI_API_KEY=$(cat ~/.tokens/openai) export GITLAB_TOKEN=$(cat ~/.tokens/gitlab) # Project paths export LLM_ROOT=~/Sites/LLM export WORKTREE_ROOT=~/Sites/.workingtrees/LLM
Package Installation
# Install dependencies npm install # Install Playwright browsers (for E2E tests) npx playwright install # Install Lefthook hooks npx lefthook install
Quick Reference
New Project Checklist
- Create
package.jsonwith standard scripts - Add
tsconfig.jsonwith strict mode - Add
.eslintrc.jsconfiguration - Add
.prettierrc.jsonconfiguration - Add
lefthook.ymlwith standard hooks - Run
npx lefthook install - Create GitLab issue for initial setup
- Use worktree for development
Common Commands
# Build npm run build # Test npm test npm run test:e2e npm run test:coverage # Lint and format npm run lint npm run format npm run typecheck # OpenAPI npm run openapi:validate npm run generate:types # Git worktree git worktree add <path> <branch> git worktree list git worktree remove <path>
Related Documentation
- NPM Packages Developer Guides
- Drupal Development Guide
- Branch Naming Standards
- Worktree Workflow
- Release Workflow
Last Updated: 2026-01-01 Version: 1.0.0