## TL;DR
The agent re-runs models because nothing tells it what changed: it shells out to `dbt run` with no selection instead of diffing. Fix it by making the agent use `dbt ls --select state:modified+` (with a prior manifest as the state) or slim CI, so only changed models and their downstream get built.

```text
agent loop: re-running the same dbt model after no-op changes
```

## Use this when
- An agent re-runs dbt models that didnt change
- Every agent iteration rebuilds the whole project
- CI runs full builds on docs-only PRs

## Not for this skill when
- The model genuinely fails (thats the model)
- Tests fail (thats the data)
- Seeds or snapshots loop (different mechanism)

## Steps

1. Show the agent how to select only what changed using state comparison:

```bash
dbt ls --select state:modified+ --state ./target-prod --target prod
```
Expected output: only models modified relative to the prod manifest, plus downstream. The agent should run this selection, not bare `dbt run`.

2. Wire the agent's run command to that selection:

```bash
dbt run --select state:modified+ --state ./target-prod
```
Expected output: unchanged models are skipped. Keep the prod manifest artifact where the agent can fetch it (CI artifact or object storage).

3. For file-watching loops, debounce and diff before running:

```bash
# agent pseudo-flow: git diff --name-only, map to models, run selection
```
Expected output: a no-op edit (whitespace, comments) maps to zero models and the agent skips the run entirely instead of rebuilding.

4. Add a guard the agent checks before any run:

```text
Before dbt run: list changed files, map to models, if empty then skip and report no-op.
```
Expected output: the loop terminates instead of spinning. Agents without this guard treat "run dbt" as an unconditional step.

## Variant phrasings

### agent rebuilds after its own formatting changes
dbt format rewrites files, which looks like a change. Exclude formatting-only diffs from the selection, or run format before the diff.

### slim CI still builds too much
`state:modified+` includes downstream; that is correct (downstream may be stale). If it is too much, the model graph needs better slicing, not a return to full builds.

## Why it happens
Agents operate step by step with no memory of what changed unless you give them a diff mechanism. `dbt run` with no selection is the path of least resistance, and dbt happily rebuilds everything. State-based selection exists precisely for this, but agents dont discover it on their own; it has to be in their instructions.

## Edge cases
- The state manifest must be fresh; a stale prod manifest makes everything look modified.
- Macro changes dont always register as model modifications; include macro paths in the diff mapping.
- Deleting a model file looks like "nothing changed" to naive diffs; handle deletions explicitly or the warehouse keeps the stale table.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_z6Nbty2oDHHJROcFMLFuOg
