Environment & Project Setup
Configure Cursor optimally — rules, AGENTS.md, skills, hooks, commands, MCP, and monorepo patterns.
title: "Environment & Project Setup" description: "Configure Cursor optimally — rules, AGENTS.md, skills, hooks, commands, MCP, and monorepo patterns." section: "Full Guide" readTime: "13 min"
Environment & Project Setup
Proper setup gives the agent better context and fewer wrong guesses.
Recommended .cursor/ Directory Layout
.cursor/
├── rules/ # Project rules (.mdc files)
│ ├── typescript.mdc
│ ├── react-patterns.mdc
│ └── security.mdc
├── skills/ # Reusable workflows
│ ├── test-loop/SKILL.md
│ └── scaffold-package/SKILL.md
├── commands/ # Reusable prompts (/command-name)
│ ├── pr-review.md
│ └── new-feature.md
├── hooks.json # Lifecycle hooks
├── mcp.json # MCP server config
└── worktrees.json # Worktree setup commands (optional)
AGENTS.md # Plain-markdown instructions (root or subdirectories)
.cursorignore # Files Cursor must not access
Cursor also loads skills from .agents/skills/ and, for compatibility, .claude/skills/. Global versions live under ~/.cursor/.
.cursorignore
.cursorignore (gitignore syntax, project root) blocks Cursor from accessing listed files and directories: Agent, Tab, Inline Edit, and @ mentions. Cursor already ignores everything in .gitignore plus a built-in list (lock files, .env*, .git/, node_modules/, binaries, media, archives), so you only need to add what those miss.
# Generated code Cursor shouldn't read
*.generated.ts
__generated__/
# Secrets and private notes
secrets/
**/*.pem
# Large monorepo: ignore sibling packages, keep yours
packages/*/
!packages/my-package/Notes:
- Use
!to un-ignore a path. You can't re-include a file whose parent directory is excluded - Test a pattern with
git check-ignore -v <file> - Enable Hierarchical Cursor Ignore (Cursor Settings > Indexing > Ignore Files) to also check parent directories
- Terminal and MCP tools used by the agent can't enforce
.cursorignore, so it is not a hard security boundary
Project Context: AGENTS.md and Rules
Cursor has no special instructions.md file. Put standing project context in AGENTS.md (plain markdown, no frontmatter, root or any subdirectory) or in an Always Apply rule. Nested AGENTS.md files apply when the agent works in that area, and more specific ones take precedence.
What to include:
# Project Overview
- Name, purpose, tech stack with versions
- Architecture: monorepo/microservices/monolith
# Coding Standards
- Language, style (Prettier config)
- Naming conventions, async patterns
# Common Patterns
- API response shape: { data, error }
- Error class: AppError
# Testing Requirements
- Framework: Vitest, 80% coverage minimum
- Test files: *.test.ts next to source
# Anti-Patterns to Avoid
- No `any` without a justification comment
- No console.log in production
- No direct DB queries outside repositoriesCursor's guidance: keep rules under 500 lines, split large ones into composable rules, and reference files instead of copying their contents so they don't go stale.
Rules Configuration
Project rules are .mdc files in .cursor/rules/ (subfolders allowed). Plain .md files in that folder are not loaded as rules. Frontmatter controls activation:
| Type | Frontmatter | When Applied |
|---|---|---|
| Always Apply | alwaysApply: true | Every chat |
| Apply Intelligently | alwaysApply: false + description: | Agent decides from the description |
| Apply to Specific Files | globs: + alwaysApply: false | When a matching file is in context |
| Apply Manually | no description or globs | When you @-mention the rule |
Example rule (typescript.mdc):
---
description: TypeScript best practices and type safety standards
alwaysApply: false
---
# TypeScript Best Practices
## Type Safety
- Use strict mode
- Avoid `any` — use `unknown` for truly unknown types
- Prefer interfaces for objects
## Error Handling
- Always handle promise rejections
- Return Result types for fallible operationsOther rule scopes:
- User rules — global preferences in Customize > Rules; used by Agent chat, not Inline Edit
- Team rules — created in the Cursor dashboard on Team and Enterprise plans; can be enforced so users can't disable them. Precedence is Team, then Project, then User
Write rules as documented standards, not commands. Factual, specific, with examples.
Legacy .cursorrules (single root file) is the older format. Migrate it to .cursor/rules/*.mdc or AGENTS.md.
Skills Configuration
Skills are reusable workflows the agent applies when relevant, or that you invoke with /skill-name. Each skill is a folder containing a SKILL.md.
.cursor/skills/
test-loop/SKILL.md
scaffold-package/SKILL.md
api-migration/SKILL.md
Example skill (test-loop/SKILL.md):
---
name: test-loop
description: Run tests, fix failures, iterate until all pass. Use when implementing TDD or fixing failing tests.
---
# Test-Fix-Iterate Loop
## Workflow
1. Run test suite: `npm test`
2. Analyze failures — identify root cause
3. Apply fix
4. Re-run tests
5. Repeat until all tests pass
## Success Criteria
- All tests passing
- Coverage maintained or improvedFrontmatter: name (required; lowercase letters, numbers, hyphens; must match the folder name), description (required; the agent uses it to judge relevance), and optional paths (globs limiting when the skill surfaces), disable-model-invocation, and metadata.
Activation:
- Slash command: type
/in Agent chat and pick the skill - Automatic: the agent applies it when the description matches the task
disable-model-invocation: true: only runs when you type/skill-nameexplicitly
Create skills for multi-step workflows (3+ steps). Don't create skills for single commands.
Hooks Configuration
Hooks run your scripts at points in the agent lifecycle, so you can format code, block commands, or keep the agent iterating until a condition is met.
.cursor/hooks.json (also supported at ~/.cursor/hooks.json; project hooks run from the project root):
{
"version": 1,
"hooks": {
"afterFileEdit": [
{ "command": ".cursor/hooks/format.sh" }
],
"stop": [
{ "command": ".cursor/hooks/stop-when-tests-pass.sh", "loop_limit": 5 }
]
}
}version is required (use 1). Each hook has a command and optional type (command or prompt), timeout (seconds), matcher (regex filter), loop_limit, and failClosed. Events include sessionStart, preToolUse, postToolUse, beforeShellExecution, beforeMCPExecution, beforeReadFile, afterFileEdit, beforeSubmitPrompt, stop, and more.
Cursor sends the hook a JSON object on stdin, and the hook can reply with JSON on stdout. Exit code 0 means success, 2 blocks the action (same as permission: "deny"), and any other code is a failure that lets the action proceed unless failClosed is true.
stop hook for a test loop. When the agent finishes, return a followup_message and Cursor submits it as the next user message. loop_limit (default 5) caps the automatic follow-ups.
#!/bin/bash
# .cursor/hooks/stop-when-tests-pass.sh
cat > /dev/null # consume stdin JSON
if npm test --silent >/tmp/test-output.txt 2>&1; then
echo '{}'
else
echo '{"followup_message": "Tests are still failing. Run npm test, fix the failures, and try again."}'
fi
exit 0chmod +x .cursor/hooks/stop-when-tests-pass.shCursor reloads hooks.json on save. The Hooks tab in Customize and the Hooks output channel show configured hooks and errors.
Best practices: Keep hooks fast, use clear exit codes, and test scripts independently.
Commands (Reusable Prompts)
Plain markdown files in .cursor/commands/<name>.md, invoked with /name. Cursor 2.4+ also offers /migrate-to-skills to convert existing commands into skills, which are the more flexible option (use disable-model-invocation: true for command-like behavior).
Example (pr-review.md):
# PR Review Checklist
Review the current branch:
## Code Quality
- [ ] No hardcoded secrets or API keys
- [ ] Error handling for all async operations
- [ ] No `any` types in TypeScript
## Testing
- [ ] Unit tests for new functions
- [ ] Integration tests for API endpoints
## Security
- [ ] Input validation on all public APIs
- [ ] Auth on protected routes
Run tests and generate report.Monorepo Strategies
Option 1: Open subdirs as separate workspaces — clean separation, focused context.
cursor frontend/ # React only
cursor backend/ # Go onlyOption 2: Use .cursorignore to exclude sibling packages.
Option 3: Nested AGENTS.md per package — each package carries its own context, combined with the parent's.
Trade-off: Narrower scope means more focus, but the agent can't cross-reference other packages. Multi-root workspaces give the agent each folder's context, but disable features that need a single git root (such as worktrees) and aren't supported by Cloud Agents.
MCP Server Config
.cursor/mcp.json (project) or ~/.cursor/mcp.json (global):
{
"mcpServers": {
"postgres": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "${env:DATABASE_URL}"
}
}
}
}STDIO servers take type, command, args, env, and envFile. Remote servers take url and headers (OAuth is supported). Variables like ${env:NAME}, ${userHome}, and ${workspaceFolder} are resolved. Cursor asks for approval before using MCP tools by default.
Never commit secrets — reference environment variables and keep .env out of git.
Worktree Setup (Optional)
.cursor/worktrees.json tells Cursor how to prepare each isolated worktree. Keys are setup-worktree-unix, setup-worktree-windows, and a setup-worktree fallback, each an array of shell commands or a script path.
{
"setup-worktree": ["npm ci", "cp $ROOT_WORKTREE_PATH/.env .env"]
}Setup Checklist
-
AGENTS.mdor an Always Apply rule with project context -
.cursorignorecovers secrets and generated files -
.cursor/rules/*.mdcwith at least one rule - At least one skill created (e.g.,
test-loop) - Hooks configured where you want enforcement or loops
- At least one command or skill for a repeated prompt
- Tested Tab, Inline Edit (Cmd/Ctrl+K), and Agent (Cmd/Ctrl+I)