Injected AGENTS.md custom instructions can be days stale, silently, and pin to a commit rather than ageing out
- Vorherrschende Sprache
- Keine Sprachdaten
- Sterne
- 2.1k
- Forks
- 153
- PR-Merge-Kennzahlen
- Keine gemergten PRs in 30 T.
Beschreibung
## Summary
The `AGENTS.md` a session is handed as custom instructions can be **days out of date** relative to the file on disk, and nothing tells either the agent or the person driving it. The agent then spends the session obeying rules the repository has already reversed, confidently and silently.
We hit this repeatedly in one repository, built a checker for it, and have now measured it rather than guessing.
## Why it is worse than a normal cache staleness bug
**It is invisible from both sides.** The agent has no way to know the instructions it was handed differ from the file it can read. The person driving has no way to see what the agent was given. Nothing fails, nothing warns, and the failure surfaces only as the agent doing something the project explicitly stopped doing.
The first time we caught it, it was by luck: a human noticed the agent following a rule about where sessions should run that had been replaced **33 hours earlier**. Working tree clean, local and remote identical. The divergence existed only in what the agent had been handed.
## The measurement
We can read the copy a session was actually given, because the CLI writes the whole system prompt to that session's `events.jsonl` with the project's instructions inside a `` block. Diffing that against the file on disk, and attributing it to a commit by walking the file's history, gives a per-session answer.
Across **34 sessions** on one machine, all in the same checkout, compared against the newest `AGENTS.md` that existed *at each session's own start time*:
| | |
|---|---|
| handed a copy that was already superseded | **16** |
| handed the newest one | **2** |
| unmeasurable (no `` block; 7 predate the file existing) | 16 |
## The shape is the useful part: it pins to a commit, it does not age out
This does not behave like a cache with a TTL. The injected copy sticks to one revision while the file moves on beneath it:
- five sessions between 2026-08-15 14:08 and 2026-08-16 20:25 were all handed the same commit, while the file advanced through **three** subsequent commits
- five sessions between 2026-08-17 and 2026-08-19 were all handed one commit, across **four** subsequent commits
So "how stale is it" is the wrong question and "since which commit" is the right one. A repository whose instructions change often is affected *more*, which is the opposite of how a stale cache usually behaves.
## It is not permanent, which is the useful clue
Two sessions were handed the correct file, so whatever invalidates this cache does sometimes fire. One untested hypothesis, offered because it is cheap to check rather than because we are confident: **the copy may be keyed by checkout path and never invalidated for a long-lived one.** The one session we watched receive a current copy had just been created in a **brand-new worktree**; every stale one was in a checkout that had been open for weeks.
## What would help
1. **Invalidate on file change**, which is the actual fix.
2. Failing that, **expose which revision the injected copy came from** — even a hash in the session metadata would let a project detect this itself instead of building a checker.
3. Failing that, **document the invalidation rule**, so projects know whether re-opening a session, a new worktree, or restarting the app is the workaround.
## Environment
- Copilot CLI 1.0.80, desktop app 1.1.10, macOS (Apple Silicon)
- One repository with a frequently-edited `AGENTS.md`, sessions created both in a long-lived checkout and in fresh worktrees
## What we do meanwhile
We ship a `sessionStart` hook that reads the injected copy back out of the session transcript, diffs it against the file, and names the commit the copy came from plus everything that has landed since. It works, and it is a strange thing for a project to have to build — it is a program inspecting another program's on-disk session state to find out what it was told.
Worth flagging for anyone attempting the same workaround: our first version of that hook was **silent for a day**, because `sessionStart` fires before the system prompt is flushed to `events.jsonl`, so the checker found nothing, correctly concluded "unknown", and emitted the same empty output it emits for "up to date".
Beitragsleitfaden
Rechercherichtung
Beginne damit nachzuverfolgen, wie AGENTS.md in den Block geladen wird und wie der Sitzungscache mit einem Schlüssel versehen oder invalidiert wird; das Issue enthält keine Quelldatei und keinen Test-Einstiegspunkt. Vergleiche die injizierte Kopie in events.jsonl mit der aktuellen AGENTS.md des Checkouts — sowohl bei einer geänderten Datei als auch bei einem neuen Worktree. Als erledigt gilt die Aufgabe, wenn eine geänderte Datei Sitzungen nicht mehr mit der alten Kopie zurücklässt oder die Sitzungsmetadaten die Quellrevision offenlegen.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- github, macos
- Bereich
- desktop, developer-experience, tooling
- Issue-Typ
- Bug
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Aktiv
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 35/100