TypeScript Project References: Teach AI Agents the Real Build Graph

TypeScript Project References: Teach AI Agents the Real Build Graph

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

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

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;
  }
}
# ✅ 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

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


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 Reply