TypeScript Project References: Teach AI Agents the Real Build Graph

TypeScript Project References: Teach AI Agents the Real Build Graph
4 views

This guide covers TypeScript project references with production-focused examples and trade-offs.

Agents that “fix types later” thrash monorepos: they edit a leaf and a root tsconfig in one breath, create cycles, and freeze CI on a full-graph typecheck. Feed them the real project-reference DAG so they patch leaves first and run tsc -b on the affected subgraph only.
⚡ TL;DR: Parse tsconfig references into a graph; give the agent the subgraph for the files it touches; require bottom-up edits; verify with tsc -b --verbose on affected projects. Reject plans that introduce new reference cycles. Pair with Cursor Agent Mode CI Gates and AST-Guided Edits.

Build the graph once per SHA — TypeScript project references

typescript
import fs from "node:fs";
import path from "node:path";

type Node = { dir: string; refs: string[] };

export function loadRefGraph(root: string): Map<string, Node> {
  const graph = new Map<string, Node>();
  const walk = (dir: string) => {
    const cfgPath = path.join(dir, "tsconfig.json");
    if (!fs.existsSync(cfgPath)) return;
    const cfg = JSON.parse(fs.readFileSync(cfgPath, "utf8"));
    const refs = (cfg.references ?? []).map((r: { path: string }) =>
      path.resolve(dir, r.path)
    );
    graph.set(path.resolve(dir), { dir: path.resolve(dir), refs });
    for (const r of refs) walk(r);
  };
  walk(root);
  return graph;
}

export function affectedProjects(graph: Map<string, Node>, files: string[]) {
  const seeds = files.map((f) => projectForFile(graph, f));
  // upstream consumers via reverse edges
  return closure(graph, seeds);
}

Agent plan gate

typescript
export function assertBottomUp(planFiles: string[], graph: Map<string, Node>) {
  const order = topoSort(affectedProjects(graph, planFiles));
  // Plan must list packages in topo order (deps before dependents)
  const planned = planFiles.map((f) => projectForFile(graph, f));
  let lastIdx = -1;
  for (const p of planned) {
    const idx = order.indexOf(p);
    if (idx < lastIdx) throw new Error(`out_of_order_edit:${p}`);
    lastIdx = idx;
  }
}
bash
# ✅ Affected build only
pnpm exec tsc -b packages/auth packages/api --verbose

# ❌ Full monorepo panic on every agent PR
pnpm exec tsc -b

Cycle detection

typescript
export function findCycles(graph: Map<string, Node>): string[][] {
  // Tarjan or Kahn — fail the agent plan if new cycle edges appear in the diff
  return tarjan(graph);
}
Expose the graph summary in Cursor notepads / repo maps so the model does not invent imports across forbidden boundaries (Cursor Notepads).

Closing checklist

✅ Dos
– ✅ Generate ref graph artifact in CI and cache per SHA
– ✅ Force topo-ordered edits
– ✅ Typecheck only affected projects on agent PRs
– ✅ Fail on new cycles in the diff ❌ Don’ts
– ❌ Don’t let agents edit composite flags casually
– ❌ Don’t path-map around references to “make tsc pass”
– ❌ Don’t typecheck the universe on every token generation

Related reading

Last updated on September 11, 2026

Related: Day 80: Project: Platform AI Gateway · Building Production AI Agents: Tool Calling, Memory, and Orchestration That Actually Work · Building AI Agents That Actually Work: The Architecture No Tutorial Shows You

Watch: 100 Days of AI on YouTube

Short videos from CheatCoders, one AI engineering topic per day.

Open the playlist on YouTube · CheatCoders on YouTube

Deep-dive PDF

Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.

Already subscribed? or open the subscribe page.


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a comment

No account needed. Name and email are optional.