Large codebases
Context strategies for repositories too big for one window. See working with large codebases.
Monorepo work with AI coding agents depends on the project graph, which Claude Code, Codex and Cursor lack by default. The Nx MCP server, Nx skills or turbo ls output supply it; a rules file adds the layering policy; and affected-only build, lint and boundary checks verify each change instead of a human reading every diff.
This page is for developers and tech leads who own a pnpm, Nx or Turborepo workspace with more than a handful of packages. You rename a type in @company/core, the agent updates the three call sites it found with grep, and CI fails in two packages you never opened because they import it through @company/ui. Or a security fix lands in the shared auth package and you cannot say which 23 services must rebuild, in what order, or which teams to tell. Both are graph questions, and an agent without the graph answers them by guessing.
If your repository is large but not split into packages, start with working with large codebases; this page assumes you already have a context strategy.
An agent reads files. It does not know that apps/web depends on @company/ui, which depends on @company/core, until something tells it. In an Nx workspace, Nx ships that something. In Turborepo and plain pnpm workspaces, you supply it from the command line.
Nx 23 has a command that configures the MCP server, skills and instruction files for each agent at once. Run it from the workspace root:
Run the configurator for the agents your team uses:
npx nx configure-ai-agents --agents claude codex cursorIf npx nx configure-ai-agents --help fails, your Nx predates the command. Migrate first, and review the migration as its own pull request before you add agent configuration on top of it; a major-version Nx migration rewrites configuration across the workspace:
npx nx migrate latestnpm install # or pnpm install / yarnnpx nx migrate --run-migrationsRead the diff before you commit it. In a test run against Nx 23.2.1, the command wrote a managed block into CLAUDE.md and AGENTS.md, seven skills under .agents/skills/ (among them nx-workspace, nx-run-tasks and nx-generate), a ci-monitor-subagent for Codex under .codex/agents/, an nx-mcp entry in .codex/config.toml that launches npx nx mcp, and a .claude/settings.json that enables the nx plugin from the nrwl/nx-ai-agents-config marketplace. It also set multi_agent = true for Codex and added sandbox allowances for ~/.nx and /tmp/.nx. Keep what you want; remove what your security policy does not allow.
Check the result later, after upgrades:
npx nx configure-ai-agents --check=allThe Cursor step needs the cursor command on your PATH; without it, the configurator skips Cursor and points you to the Nx Console extension. The manual entries in the next section work in every case.
Use this when you do not run the configurator, or when you want a pinned version. Pin it: in August 2025, malicious nx versions were published to npm that scanned the file system for credentials (Nx security advisory GHSA-cxm3-wv7p-598c, 2025-08-27), and npx -y with no version runs whatever is newest.
Add the server at project scope so the entry lands in a shared .mcp.json that you commit, instead of the default local scope in your own ~/.claude.json:
claude mcp add nx --scope project -- npx -y nx-mcp@0.25.0 --no-minimalclaude mcp listThe options (--scope, -e, --transport) go before the server name; everything after -- is the launch command.
codex mcp add nx -- npx -y nx-mcp@0.25.0 --no-minimalcodex mcp listThe entry is written to ~/.codex/config.toml, which only you see. To share it with the team, put the same [mcp_servers.nx] block in the workspace’s .codex/config.toml and commit it; Codex loads a project config only for trusted projects (see the AGENTS.md item under troubleshooting).
Codex 0.157.1 waits 30 seconds for a server to start (measured 2026-09-30 against a server that never answers). On a large workspace the first graph computation can take longer, so raise the limit above the default:
[mcp_servers.nx]command = "npx"args = ["-y", "nx-mcp@0.25.0", "--no-minimal"]startup_timeout_sec = 60Add the server to .cursor/mcp.json at the workspace root and commit the file:
{ "mcpServers": { "nx": { "command": "npx", "args": ["-y", "nx-mcp@0.25.0", "--no-minimal"] } }}Confirm under the MCP section of Cursor’s settings that nx is listed and enabled.
For the wider MCP picture (security, token cost, other servers) see the MCP ecosystem guides.
Turborepo 2.11 has no MCP server of its own, but its CLI answers the same questions, and every agent can run it:
npx turbo ls --output json # every package, as JSON (--output is experimental)npx turbo ls --filter=...@company/core # a package plus everything that depends on itnpx turbo ls --affected # packages changed since `main`, plus their dependentsnpx turbo run build --affected --dry-run # the task graph turbo would run, without running it--affected compares against main, so it only has something to report once files have changed. To plan a change before any edit, use the --filter=...<package> form. Put these commands in the rules file (next section) so the agent runs them before it plans, instead of inferring the graph from import statements.
The graph records what depends on what. It does not record what is allowed: that apps never import from other apps, that core has no external dependencies, that exported types change only through a deprecation. Without that policy, an agent resolves a circular import by adding the edge that creates it.
Put the policy in the root CLAUDE.md and package-specific rules in each package’s own CLAUDE.md, which Claude Code loads when it works in that directory:
# CLAUDE.md (root)pnpm + Turborepo monorepo. Layers, lowest first: packages/core -> packages/ui, packages/api-client -> apps/web, apps/api, apps/adminHard rules:- packages/* MUST NOT import from apps/*. apps/* MUST NOT import from each other.- packages/core MUST NOT gain external runtime dependencies.- Exported types change only by adding a deprecated alias first.Before planning a cross-package change: run `npx turbo ls --filter=...<changed package> --output json` to list the package and its dependents.After changing a package: `npx turbo run build test --filter=...@company/core`(the leading `...` selects the package and everything that depends on it).Codex reads AGENTS.md files before doing any work. Use the same policy, written as the order of operations Codex should follow:
Layers, lowest first: core -> ui, api-client -> web, api, admin.packages/* MUST NOT import from apps/*; apps MUST NOT import from each other.For any cross-package change:1. Run `npx turbo ls --filter=...<changed package> --output json` to list the package and its dependents, in layer order.2. Change the lowest layer first; build and test it before touching dependents.3. Finish with `npx turbo run build test lint --affected`.Add a project rule under .cursor/rules/ that always applies, and give it the same body as the Codex tab. To scope a package’s conventions to its directory, see Cursor’s Rules documentation.
Phrase layering rules as prohibitions (“MUST NOT import”), not descriptions (“apps usually use packages”). Then enforce the same rule in lint (see how to prove a cross-package change), because a rules file is advice and a lint rule is a gate.
The most valuable monorepo prompt asks what breaks before any file changes. With the graph available, the agent returns packages in rebuild order, not a list of grep hits.
Check the answer cheaply. Before any edit, in a Turborepo or pnpm workspace, the package list must match npx turbo ls --filter=...@company/core. After the change, it must match npx nx show projects --affected or npx turbo ls --affected. If the agent lists a package the tool does not, or misses one, its graph read was wrong. Stop and fix the context before it goes further.
A cross-package change stays small only if each layer compiles before the next one changes. The sequence is the same in all three tools; what differs is how you run the layers in parallel.
Get the plan. Run the impact prompt and compare its package list with the tool’s own list of dependents (npx turbo ls --filter=...<package>, or the Nx project graph).
Change the lowest package and build it alone — for example npx nx build @company/core or npx turbo run build --filter=@company/core — before any dependent sees the change.
Add a compatibility shim. Keep the old name as a deprecated alias so every layer above still compiles while you migrate it.
Migrate one layer at a time. Build and test each layer before the agent moves up. A failure then points at one package, not five.
Run the affected gate (next section), then remove the shim in a separate, small change.
Without a graph server, you give the agent the order yourself. The hard stop after the listing step replaces the check the graph would have done:
Parallel layers. Once the lowest layer has landed, the packages in the next layer that do not depend on each other can each run in their own worktree. Check first: npx turbo ls <package> lists a package’s dependencies, and the Nx graph shows the same. In the layer order from the rules file above, if ui imports types from api-client, the two run in sequence, not in parallel. Start one worktree per independent package: claude --worktree ui-migration in Claude Code, codex --worktree in Codex, or Cursor’s Worktrees. Never parallelize across layers; a dependent built against an unmerged dependency proves nothing. The parallel agents guide covers the orchestration side.
A 40-package rename produces a diff nobody reads line by line, and nobody should have to. Four checks carry the evidence; the package owners sign off on the parts that need a human.
| Check | Command or mechanism | What it proves | Who acts on a failure |
|---|---|---|---|
| Affected build, test, lint | npx nx affected -t build test lint --base=origin/main or npx turbo run build test lint --affected | Every dependent compiles and passes its tests against the new code | The agent fixes; you rerun |
| Module boundaries | Nx: the @nx/enforce-module-boundaries rule from @nx/eslint-plugin with project tags. Other workspaces: a dependency-rule check such as dependency-cruiser (npm install --save-dev dependency-cruiser, then npx depcruise --init), run as a fitness function | No forbidden import was added to make something compile | The agent fixes; a new exception needs the tech lead |
| Graph diff | Nx: npx nx graph --file=before.json on the base branch and --file=after.json on the change. Turborepo: the turbo query command below, redirected to before.json and after.json | Which dependency edges were added or removed | The owner of each package that gained an edge approves it (CODEOWNERS) |
| Full pipeline | Your normal CI run on the merge request | Nothing outside the affected set broke | Normal CI ownership |
In a Turborepo workspace, turbo ls --output json without package names lists only names and paths, not edges. Ask turbo query for the edges instead (checked with turbo 2.11.5, 2026-09-30):
npx turbo query '{ packages { items { name directDependencies { items { name } } } } }' > before.jsonThe graph diff is the check that replaces reading. A rename should add no edges. If apps/admin now depends on apps/web, the diff shows it in one line, however large the code change. Turn boundary rules into CI gates with architecture fitness functions, and attach the four results to the pull request as an evidence bundle.
Monorepos drift quietly: one package on another TypeScript version, one tsconfig.json that stopped extending the base, one test target whose inputs include Markdown, so every doc edit invalidates the cache. Run the audit monthly, or in a scheduled agent job, rather than after an incident.
Measure any task-graph fix before you accept it: compare the run time of the same affected build before and after, on the same CI runner. An agent’s estimate of time saved is a guess.
Publishing @company/payments before the @company/core version it needs ships a broken package. Let Changesets own the versioning mechanics and use the agent to draft the changesets and check the order.
Then a human runs npx changeset version and npx changeset publish from CI. Keep publishing out of the agent’s hands; it is the one step you cannot roll back with git revert.
claude mcp list or codex mcp list. A failed server usually means npx is missing from the PATH the agent inherits, or it timed out while computing the graph. Fix the PATH, or raise startup_timeout_sec in Codex above its 30-second default, for example to 60.nx configure-ai-agents, or add --no-minimal.nx.json, or pass the workspace path as the first argument: npx nx-mcp@0.25.0 /path/to/workspace.npx nx reset, which clears the cache and shuts down the Nx daemon (it restarts on the next command), then ask the agent to read the graph again....@company/core filter to the rules file, and make the affected gate a required CI check.nx affected or turbo run --affected), not only the package you edited.AGENTS.md. Since Codex CLI 0.150.0, untrusted projects no longer supply project-level AGENTS.md instructions. Mark the workspace as trusted when Codex asks, then start a new session.--base to narrow nx affected.nx configure-ai-agents changed more than you expected. It can enable a Claude Code plugin marketplace, Codex multi-agent mode and sandbox allowances. Review .claude/settings.json and .codex/config.toml in the diff like any other dependency change.Large codebases
Context strategies for repositories too big for one window. See working with large codebases.
Fitness functions
Turn layering rules into CI checks the agent cannot argue with. See architecture fitness functions.
Microservices
The same graph-first approach across service boundaries. See microservices workflows.
CI/CD pipelines
Wire the affected gate and the release step into CI. See pipeline automation with AI.
Agent-ready codebase
Rules files, commands and checks that make any repository easier for agents. See making a codebase agent-ready.