chore(agent): configure AI agents and tools
Add configuration for BMad, Claude, OpenCode, and other AI agent tools and workflows.
This commit is contained in:
348
.agent/skills/turborepo/references/configuration/gotchas.md
Normal file
348
.agent/skills/turborepo/references/configuration/gotchas.md
Normal file
@@ -0,0 +1,348 @@
|
||||
# Configuration Gotchas
|
||||
|
||||
Common mistakes and how to fix them.
|
||||
|
||||
## #1 Root Scripts Not Using `turbo run`
|
||||
|
||||
Root `package.json` scripts for turbo tasks MUST use `turbo run`, not direct commands.
|
||||
|
||||
```json
|
||||
// WRONG - bypasses turbo, no parallelization or caching
|
||||
{
|
||||
"scripts": {
|
||||
"build": "bun build",
|
||||
"dev": "bun dev"
|
||||
}
|
||||
}
|
||||
|
||||
// CORRECT - delegates to turbo
|
||||
{
|
||||
"scripts": {
|
||||
"build": "turbo run build",
|
||||
"dev": "turbo run dev"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why this matters:** Running `bun build` or `npm run build` at root bypasses Turborepo entirely - no parallelization, no caching, no dependency graph awareness.
|
||||
|
||||
## #2 Using `&&` to Chain Turbo Tasks
|
||||
|
||||
Don't use `&&` to chain tasks that turbo should orchestrate.
|
||||
|
||||
```json
|
||||
// WRONG - changeset:publish chains turbo task with non-turbo command
|
||||
{
|
||||
"scripts": {
|
||||
"changeset:publish": "bun build && changeset publish"
|
||||
}
|
||||
}
|
||||
|
||||
// CORRECT - use turbo run, let turbo handle dependencies
|
||||
{
|
||||
"scripts": {
|
||||
"changeset:publish": "turbo run build && changeset publish"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the second command (`changeset publish`) depends on build outputs, the turbo task should run through turbo to get caching and parallelization benefits.
|
||||
|
||||
## #3 Overly Broad globalDependencies
|
||||
|
||||
`globalDependencies` affects hash for ALL tasks in ALL packages. Be specific.
|
||||
|
||||
```json
|
||||
// WRONG - affects all hashes
|
||||
{
|
||||
"globalDependencies": ["**/.env.*local"]
|
||||
}
|
||||
|
||||
// CORRECT - move to specific tasks that need it
|
||||
{
|
||||
"globalDependencies": [".env"],
|
||||
"tasks": {
|
||||
"build": {
|
||||
"inputs": ["$TURBO_DEFAULT$", ".env*"],
|
||||
"outputs": ["dist/**"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why this matters:** `**/.env.*local` matches .env files in ALL packages, causing unnecessary cache invalidation. Instead:
|
||||
|
||||
- Use `globalDependencies` only for truly global files (root `.env`)
|
||||
- Use task-level `inputs` for package-specific .env files with `$TURBO_DEFAULT$` to preserve default behavior
|
||||
|
||||
## #4 Repetitive Task Configuration
|
||||
|
||||
Look for repeated configuration across tasks that can be collapsed.
|
||||
|
||||
```json
|
||||
// WRONG - repetitive env and inputs across tasks
|
||||
{
|
||||
"tasks": {
|
||||
"build": {
|
||||
"env": ["API_URL", "DATABASE_URL"],
|
||||
"inputs": ["$TURBO_DEFAULT$", ".env*"]
|
||||
},
|
||||
"test": {
|
||||
"env": ["API_URL", "DATABASE_URL"],
|
||||
"inputs": ["$TURBO_DEFAULT$", ".env*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BETTER - use globalEnv and globalDependencies
|
||||
{
|
||||
"globalEnv": ["API_URL", "DATABASE_URL"],
|
||||
"globalDependencies": [".env*"],
|
||||
"tasks": {
|
||||
"build": {},
|
||||
"test": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**When to use global vs task-level:**
|
||||
|
||||
- `globalEnv` / `globalDependencies` - affects ALL tasks, use for truly shared config
|
||||
- Task-level `env` / `inputs` - use when only specific tasks need it
|
||||
|
||||
## #5 Using `../` to Traverse Out of Package in `inputs`
|
||||
|
||||
Don't use relative paths like `../` to reference files outside the package. Use `$TURBO_ROOT$` instead.
|
||||
|
||||
```json
|
||||
// WRONG - traversing out of package
|
||||
{
|
||||
"tasks": {
|
||||
"build": {
|
||||
"inputs": ["$TURBO_DEFAULT$", "../shared-config.json"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CORRECT - use $TURBO_ROOT$ for repo root
|
||||
{
|
||||
"tasks": {
|
||||
"build": {
|
||||
"inputs": ["$TURBO_DEFAULT$", "$TURBO_ROOT$/shared-config.json"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## #6 MOST COMMON MISTAKE: Creating Root Tasks
|
||||
|
||||
**DO NOT create Root Tasks. ALWAYS create package tasks.**
|
||||
|
||||
When you need to create a task (build, lint, test, typecheck, etc.):
|
||||
|
||||
1. Add the script to **each relevant package's** `package.json`
|
||||
2. Register the task in root `turbo.json`
|
||||
3. Root `package.json` only contains `turbo run <task>`
|
||||
|
||||
```json
|
||||
// WRONG - DO NOT DO THIS
|
||||
// Root package.json with task logic
|
||||
{
|
||||
"scripts": {
|
||||
"build": "cd apps/web && next build && cd ../api && tsc",
|
||||
"lint": "eslint apps/ packages/",
|
||||
"test": "vitest"
|
||||
}
|
||||
}
|
||||
|
||||
// CORRECT - DO THIS
|
||||
// apps/web/package.json
|
||||
{ "scripts": { "build": "next build", "lint": "eslint .", "test": "vitest" } }
|
||||
|
||||
// apps/api/package.json
|
||||
{ "scripts": { "build": "tsc", "lint": "eslint .", "test": "vitest" } }
|
||||
|
||||
// packages/ui/package.json
|
||||
{ "scripts": { "build": "tsc", "lint": "eslint .", "test": "vitest" } }
|
||||
|
||||
// Root package.json - ONLY delegates
|
||||
{ "scripts": { "build": "turbo run build", "lint": "turbo run lint", "test": "turbo run test" } }
|
||||
|
||||
// turbo.json - register tasks
|
||||
{
|
||||
"tasks": {
|
||||
"build": { "dependsOn": ["^build"], "outputs": ["dist/**"] },
|
||||
"lint": {},
|
||||
"test": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why this matters:**
|
||||
|
||||
- Package tasks run in **parallel** across all packages
|
||||
- Each package's output is cached **individually**
|
||||
- You can **filter** to specific packages: `turbo run test --filter=web`
|
||||
|
||||
Root Tasks (`//#taskname`) defeat all these benefits. Only use them for tasks that truly cannot exist in any package (extremely rare).
|
||||
|
||||
## #7 Tasks That Need Parallel Execution + Cache Invalidation
|
||||
|
||||
Some tasks can run in parallel (don't need built output from dependencies) but must still invalidate cache when dependency source code changes. Using `dependsOn: ["^taskname"]` forces sequential execution. Using no dependencies breaks cache invalidation.
|
||||
|
||||
**Use Transit Nodes for these tasks:**
|
||||
|
||||
```json
|
||||
// WRONG - forces sequential execution (SLOW)
|
||||
"my-task": {
|
||||
"dependsOn": ["^my-task"]
|
||||
}
|
||||
|
||||
// ALSO WRONG - no dependency awareness (INCORRECT CACHING)
|
||||
"my-task": {}
|
||||
|
||||
// CORRECT - use Transit Nodes for parallel + correct caching
|
||||
{
|
||||
"tasks": {
|
||||
"transit": { "dependsOn": ["^transit"] },
|
||||
"my-task": { "dependsOn": ["transit"] }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why Transit Nodes work:**
|
||||
|
||||
- `transit` creates dependency relationships without matching any actual script
|
||||
- Tasks that depend on `transit` gain dependency awareness
|
||||
- Since `transit` completes instantly (no script), tasks run in parallel
|
||||
- Cache correctly invalidates when dependency source code changes
|
||||
|
||||
**How to identify tasks that need this pattern:** Look for tasks that read source files from dependencies but don't need their build outputs.
|
||||
|
||||
## Missing outputs for File-Producing Tasks
|
||||
|
||||
**Before flagging missing `outputs`, check what the task actually produces:**
|
||||
|
||||
1. Read the package's script (e.g., `"build": "tsc"`, `"test": "vitest"`)
|
||||
2. Determine if it writes files to disk or only outputs to stdout
|
||||
3. Only flag if the task produces files that should be cached
|
||||
|
||||
```json
|
||||
// WRONG - build produces files but they're not cached
|
||||
"build": {
|
||||
"dependsOn": ["^build"]
|
||||
}
|
||||
|
||||
// CORRECT - outputs are cached
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["dist/**"]
|
||||
}
|
||||
```
|
||||
|
||||
No `outputs` key is fine for stdout-only tasks. For file-producing tasks, missing `outputs` means Turbo has nothing to cache.
|
||||
|
||||
## Forgetting ^ in dependsOn
|
||||
|
||||
```json
|
||||
// WRONG - looks for "build" in SAME package (infinite loop or missing)
|
||||
"build": {
|
||||
"dependsOn": ["build"]
|
||||
}
|
||||
|
||||
// CORRECT - runs dependencies' build first
|
||||
"build": {
|
||||
"dependsOn": ["^build"]
|
||||
}
|
||||
```
|
||||
|
||||
The `^` means "in dependency packages", not "in this package".
|
||||
|
||||
## Missing persistent on Dev Tasks
|
||||
|
||||
```json
|
||||
// WRONG - dependent tasks hang waiting for dev to "finish"
|
||||
"dev": {
|
||||
"cache": false
|
||||
}
|
||||
|
||||
// CORRECT
|
||||
"dev": {
|
||||
"cache": false,
|
||||
"persistent": true
|
||||
}
|
||||
```
|
||||
|
||||
## Package Config Missing extends
|
||||
|
||||
```json
|
||||
// WRONG - packages/web/turbo.json
|
||||
{
|
||||
"tasks": {
|
||||
"build": { "outputs": [".next/**"] }
|
||||
}
|
||||
}
|
||||
|
||||
// CORRECT
|
||||
{
|
||||
"extends": ["//"],
|
||||
"tasks": {
|
||||
"build": { "outputs": [".next/**"] }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Without `"extends": ["//"]`, Package Configurations are invalid.
|
||||
|
||||
## Root Tasks Need Special Syntax
|
||||
|
||||
To run a task defined only in root `package.json`:
|
||||
|
||||
```bash
|
||||
# WRONG
|
||||
turbo run format
|
||||
|
||||
# CORRECT
|
||||
turbo run //#format
|
||||
```
|
||||
|
||||
And in dependsOn:
|
||||
|
||||
```json
|
||||
"build": {
|
||||
"dependsOn": ["//#codegen"] // Root package's codegen
|
||||
}
|
||||
```
|
||||
|
||||
## Overwriting Default Inputs
|
||||
|
||||
```json
|
||||
// WRONG - only watches test files, ignores source changes
|
||||
"test": {
|
||||
"inputs": ["tests/**"]
|
||||
}
|
||||
|
||||
// CORRECT - extends defaults, adds test files
|
||||
"test": {
|
||||
"inputs": ["$TURBO_DEFAULT$", "tests/**"]
|
||||
}
|
||||
```
|
||||
|
||||
Without `$TURBO_DEFAULT$`, you replace all default file watching.
|
||||
|
||||
## Caching Tasks with Side Effects
|
||||
|
||||
```json
|
||||
// WRONG - deploy might be skipped on cache hit
|
||||
"deploy": {
|
||||
"dependsOn": ["build"]
|
||||
}
|
||||
|
||||
// CORRECT
|
||||
"deploy": {
|
||||
"dependsOn": ["build"],
|
||||
"cache": false
|
||||
}
|
||||
```
|
||||
|
||||
Always disable cache for deploy, publish, or mutation tasks.
|
||||
Reference in New Issue
Block a user