Research & Product Philosophy Living Document · Rev. July 2026

The Observer

An AI that watches a developer's whole arc of work and reflects intent-drift back to them — without ever competing for the cognition that produced it.

Name AI Observer CLI Tool Started July 2026 Status ongoing — not a finished artifact Phase observability confirmed · v1 spec written
On the status of this document

This is not a finished study. The document grows alongside the tool itself — it begins as market and problem research (the current phase), and as the work moves into technical spec, prototype, MVP, testing, and real users, each phase's findings are added here rather than replacing what came before. The end state is a complete research record — problem, philosophy, design decisions, what was tried, what testing and real users showed — meant to be publishable, possibly alongside the tool when it ships. Every section below is current best understanding, not settled history.

The core principle
AI should witness, not compete for cognition.
Not a feature description. A stance on what AI is for in a development workflow — and it is stated in opposition to nearly everything currently being built.
Abstract

Cognitive drift is what happens when AI-assisted development lets output outrun understanding — a thousand small, locally-reasonable acceptances that compound into a system nobody actually chose. Every current tool responds by adding another AI to the loop: more specs, more agents, more synchronization. The Observer takes the opposite position. It watches a Claude Code session in VS Code — the spec you gave it, the prompt you wrote, what the AI produced, what you did next — and the moment a seam opens between what you meant and what is happening, it shows a quiet flag. It never writes, suggests, or scores. Its only job is to make sure you still recognize what you are building, and why.

§1 — The core idea, stated precisely

What the tool is, and what it refuses to be

The Observer is not a linter, a spec-sync tool, or a second AI coding assistant. It is something that watches a developer's whole arc of work — the task, the reason for the task, where it is headed, how it touches the current and future state of the system — and periodically reflects that back, so the developer can see whether they have drifted from their own plan.

The one-line version is the right one: AI should witness, not compete for cognition. That is not a feature description. It is a claim about the role AI should play in a workflow, and it is deliberately stated against the grain of the current market.

§2 — What "cognitive drift" actually means here

Five layers of drift, five different ways a developer notices

Cognitive drift, defined precisely: everything related to the current task — why you are doing it, where it leads, how it affects current and future state — and whether what you are doing now has drifted from your original plan as AI assistance accumulates. It is worth separating this into layers, because each is a different engineering problem and a different reason a developer notices something has gone wrong.

Layer The drift How it's noticed today
Intent decay You forget why you made a decision six days or six weeks ago Git-blame archaeology, Slack search, staring at a comment that no longer makes sense
Plan drift The system diverges from your intended architecture, one AI-accepted suggestion at a time A sudden "wait, why does it look like this now"
Task drift Mid-session, you've solved a different problem than the one you sat down to solve Realizing at 6pm that the ticket is still open
State drift Your mental model of the codebase no longer matches what's actually in it A bug that "shouldn't be possible" given what you thought was true
Compounding drift Small, locally-reasonable steps that add up to something nobody would have chosen on purpose The "how did we end up here" retrospective

This framing matters because it says the tool is not solving one problem. It is solving the meta-problem: that these small divergences are invisible in the moment and only legible in hindsight — usually someone else's hindsight, in a postmortem.

§3 — The landscape as it exists in mid-2026

A crowded field — and a precise gap in the middle of it

This space got crowded fast. It is worth knowing exactly how, so as not to rebuild something that already exists — and so the gap becomes visible.

3.1  "Drift" is already an industry term — but it means something narrower

Across the current ecosystem, "drift" almost always means one thing: the AI agent's output no longer matches a written specification.

  • Spec-Driven Development (SDD) treats the spec as the source of truth and code as downstream of it; drift is when implementation diverges from spec.
  • Intent-Driven Development (IDD) tools (Augment's "Intent,"8 OpenSpec, others) maintain a "Decision Layer" between intent and code and explicitly watch for code or decisions drifting from written intent — but by their own account this only catches drift if someone maintains the spec, and over time incremental changes accumulate decisions that "made sense in isolation but don't hold up when viewed holistically."5
  • "ContextOps" (Packmind and similar) treats context files (CLAUDE.md, .cursor rules, etc.) as an organizational asset and runs "automated drift detection, pre-commit enforcement, and cross-file consistency checks" against them.6
  • "Intent drift" in QA tooling (Tricentis and others) is about production code: "a silent failure mode of AI-assisted development, where behavior gradually diverges from specification without necessarily breaking a test or failing a pipeline."7
  • API / spec tooling (SmartBear/Swagger) now sells drift detection for the literal gap between an API spec and the code that implements it.

Notice what these share: the artifact being checked is a document — a spec, a rules file, an API contract. The checker is another AI agent or a static analyzer. The audience is a pipeline, a reviewer, or a team lead. None of them are checking for drift in the developer's own head.

3.2  The closest conceptual neighbor: "black box AI drift"

One essay gets unusually close. A Stack Overflow contributor describes "black box AI drift — the gap between what you need in a design and the AI translation of your intent into code," arguing that prompts go in, output comes out, and the decisions made in between are hidden from view — and because of the volume and velocity of AI-assisted generation, those gaps are proliferating faster than we can chase them.4

This is close. But its proposed fix is still tool-side: making the AI's own reasoning visible. The Observer's is developer-side: making the developer's drift from their own intent visible. That is a meaningfully different product, even if it starts from the same anxiety.

3.3  DevEx research already names the underlying condition

Developer-experience research has isolated the three variables this tool is implicitly designed around: feedback loops (the speed at which developers receive information about their work), cognitive load (the mental effort required to complete tasks), and flow state (the state of full immersion and enjoyment).1 Critically, recent longitudinal work notes that how AI coding assistants affect flow state is not yet well understood.2 This is a young, unsettled area — not a solved one.

There is real evidence that AI assistants can be net-negative for flow specifically because of the interruption pattern, not the assistance itself. The same longitudinal study reports a productivity–experience paradox: productivity perceptions held stable (84% reporting improvement at both time points), yet among matched participants the proportion reporting worsened developer experience in at least one dimension nearly doubled, from 14% to 27%, with flow state and cognitive load eroding even as feedback loops improved.2

"Unwanted or poorly timed suggestions, verbose outputs, interface switching, and the need to constantly verify generated code introduce frequent interruptions that break developers' flow continuity."
And the cost is non-linear — even a modest interruption rate of 10% can nearly double total task completion time.3

This is the empirical case for the principle. Every existing AI dev tool adds a participant to the developer's cognition; the evidence says that is exactly what damages flow and inflates cognitive load. A tool whose entire design constraint is "never interrupt, never suggest, only reflect back on request" argues directly against the grain of where the industry is building — and the research suggests the grain is wrong.

3.4  The "AI as participant" assumption is nearly universal — and increasingly contested

Design research on human–AI collaboration keeps circling the same discomfort. In one recent study, designers reacted to a hypothetical AI agent that could act autonomously mid-task; the pushback was consistent — one participant said they would want to stay in control at that stage rather than let the agent "listen and execute," and another insisted the AI should always leave the last decision to the human.9 Tellingly, when it came to a tool meant to hold onto a person's own material — the closest existing analogue to an observer archive — the same participants were unambiguous: such a tool is useful only as long as it is user-controlled, user-generated, and user-owned.9

That is close to the "code ownership vs. allowed ownership" thinking behind this project. It suggests the appetite for a tool that only holds up a mirror — without asserting authorship, suggestion, or authority over the work — is already there, articulated by people who do not yet have a name for what they are asking for.

3.5  No one has claimed "witness, not participant" as positioning

Checked directly for this framing and adjacent ones. Nothing in the current market — spec tools, IDD platforms, context-ops platforms, observability-for-devex tools — states this as a philosophy. Without exception they position themselves as making the AI more involved, more synchronized, more embedded in the loop. That phrase, and the stance behind it, is open ground as of today.

§4 — Why this gap exists (and why it's real, not just unclaimed)

Three honest reasons nobody has built this yet

  1. 1It's commercially awkward. Almost every AI dev-tool company is funded on the premise of the AI doing more, faster, with more autonomy. A tool whose selling point is "does less, says less, waits to be asked" cuts against the dominant investment thesis. That is exactly why it is differentiated — but it also means there is no ready playbook for how to price or grow it.
  2. 2It's technically harder to make legible than it sounds. Detecting spec-vs-code drift is comparatively mechanical: diff the spec, diff the code, flag the mismatch. Detecting intent drift — whether today's work still serves the reason the developer started — requires modeling something that was never written down in a machine-readable form. You are not comparing two documents; you are comparing a developer's present actions to a past mental state that only ever existed in their head, maybe partially externalized in a commit message, a ticket, or a stray comment.
  3. 3The moment of reflection has to be earned, not imposed. The flow-state research is unambiguous that interruption is the enemy. So the entire mechanism of "showing the developer their own drift" has to happen on the developer's terms — pulled, not pushed — or it becomes just another notification competing for attention, which is the exact failure mode the tool is positioned against.
§4.5 — Correction: "pulled, not pushed" was stated imprecisely

The real distinction is interruption vs. ambient presence

An earlier draft argued that reflection should be "retrospective and requested, not real-time and pushed," and implied the interface problem was the hardest part of the whole idea. Both were quietly overreaching, and it is worth naming exactly how — because the correction is the product.

The real distinction isn't "during the session" vs. "after the session." It's interruption vs. ambient presence.

Interruption

A popup, a modal, a sound, a notification badge that demands a reaction now. This is the mechanism the flow-state research condemns — the poorly-timed suggestion that breaks flow continuity.

Ambient presence

A small, silent, passive indicator — a dot changes color — sitting in peripheral vision, asking nothing until you choose to look. Closer to a git status light or a linter gutter mark than to a suggestion engine.

A tool can watch and flag during the session without ever interrupting, as long as the signal is visual, small, silent, and entirely optional to check. That is fully consistent with "witness, not participant" — the witness is present in the room the whole time, but never taps you on the shoulder. It speaks only when you turn and ask.

So the design rule is: the tool may change its own indicator state at any moment; it may never demand attention at any moment. To be unambiguous about scope — it only ever changes its own flag state (on/off). It never touches the developer's code, files, or environment, under any circumstance. That is not a feature limitation to justify; it is simply outside what a witness does.

On the "hardest design problem" claim specifically: the original draft framed "how to show drift without a dashboard" as the hardest open problem in the product. That framing was itself an unrequested drift — it had already been settled that there should be no metric, no score, no KPI, only a sentence. Turning that into an open "hard problem" quietly reintroduced the very thing that had been ruled out. The correct standing answer, stated once:

There is no metric. There is no dashboard. There is a sentence.

Something like: "The task was to decrease the margin. You're changing the background color of a neighboring element." Plain, specific, comparing stated intent to observed action, in the developer's own terms — not a number, not a severity score beyond a simple flag color, not a trend line. If a red or yellow indicator appears, clicking it reveals one sentence. That is the entire surface area of the output. (This is refined further in §8 — the default view is now a raw comparison, with the generated sentence available only as a clearly-labeled secondary action.)

§5 — What this suggests for the tool (a starting map, not a prescription)

The unit of observation, the seams, and where the tool watches

What the tool should watch and ingest is genuinely still open. But the research narrows the space of good answers.

Faithfulness, not quality — stated explicitly

The Seam B example (AI adds unrequested tests) matters beyond illustrating the mechanism: it establishes that this tool has no opinion on whether the AI's output was good. Only on whether it was asked for. If a developer's own prompt was flawed, or their next step is a mistake, the tool has nothing to say — that mistake is theirs, made knowingly, by their own hand. The tool's entire value is that when something goes wrong, the developer can trace it back to a decision they actually made, not one that was quietly made for them. Faithfulness to stated intent is the only axis this tool measures. Quality is out of scope, permanently.

Seam A — the false case, stated concretely

The true case (a prompt that traceably connects to a spec fragment) was defined first; the false case needs its own definition, by the same standard used for Seams B and C: "still the same task" is false when the prompt's content has no traceable connection to any part of SPEC.md — for example, a prompt that introduces a new external API, a new tool, or a design-system change nowhere referenced in the spec.

This is deliberately framed as "no traceable connection," not "introduces something new" — because a spec can be incomplete, and a developer introducing something the spec never anticipated may be entirely correct to do so. The tool cannot and should not try to distinguish "developer went off-spec" from "spec didn't anticipate this and the developer is right to deviate." Those two cases get names of their own — new-but-justified vs. new-but-drifted — in §7, where it is decided that the distinction belongs to the developer's judgment, not the tool's logic. The tool only reports the absence of a traceable connection; what that absence means is the developer's call.

It is also worth noting when Seam A drift is likely to occur: rarely on the first prompt of a task (which tends to cleanly reference the spec), and increasingly as a session goes on — new ideas surface mid-development, and a few unrelated asks get folded into an otherwise-correct prompt. Seam A checks may need to matter more, not less, as a session lengthens.

Worked example · Seam C · scope creep
SPEC.md"Build a new pricing component."
prompt 1Scaffold the pricing card component  // traceable → passes
editsdeveloper begins wiring up a Stripe integration — checkout, webhooks, a customer table
seamno traceable connection to SPEC.md → flag opens

An early next-step check could have passed cleanly — the first prompt referenced the spec perfectly. The drift emerged several edits later, within the same apparent task. Nobody chose "let's rebuild payments today"; it accumulated. This is exactly the case that makes single-point checks insufficient (see the re-checking open question, §8).

Open question, adjacent to Seam A: how authoritative is SPEC.md, and for how long?

A real question surfaced during this research: at what point does a developer have the standing right to explore, trial-and-error, or research something unrelated to the spec, without that being treated as drift? This is not a detection-mechanism question (that is what Seam A answers) — it is a policy/usage question about how strictly any given developer or team wants their own spec to bind them, and whether that strictness can flex mid-session (e.g., an explicit "exploration mode" toggle vs. spec-as-law throughout). The tool should not answer this on the developer's behalf. But the concept doc should eventually state whether v1 assumes spec-as-constant-authority or builds in a declared exploration window. Left open for now — addressed in full in §7.

Partial-match ambiguity — flagged as unresolved, not answered

All worked examples so far describe clean matches or clean mismatches. Real sessions will produce partial matches — a prompt related to the spec but scope-expanded (spec says "component," prompt says "component plus basic validation"). Whether that counts as drift, a soft flag, or no flag at all is not yet decided, and should not be treated as implicitly resolved by the clean-case examples.

The concrete MVP shape — now confirmed rather than assumed

A local Observer daemon — a simple CLI tool at heart — listening on HTTP, fed entirely by Claude Code's own hook system (UserPromptSubmit, Stop, PostToolUse). This works identically whether the developer is using the Claude Code CLI directly or its VS Code sidebar — the daemon doesn't care which surface sent the event, and doesn't need to be a VS Code extension to function. An extension, if built later, is a UI layer on top of this daemon, not a requirement for it.

Seam C — AI output vs. the developer's own next step, its original and only definition — cannot be fully closed by the hook system alone; the independent file-watcher needed to close it is explicitly not part of this MVP shape, deferred to a future version (see §4.6 and §4.8). This is a gap in what's observable, not a redefinition of what Seam C means. MVP is a single, well-instrumented environment rather than an attempt to watch "development" in the abstract — and it is now grounded in tested behavior rather than a hoped-for API.

The unit of observation is the task loop, repeated

Drift can appear at any seam between these four stages. The tool's job is to sit across all four and notice when a seam has opened.

1Intent — whatever the developer provides as input: an .md, a .pdf, pasted or typed text, a prompt written directly into the session — any combination. The one and only source of truth for "what was supposed to happen." No inference, no guessing at unstated goals.
2Prompt — what the developer actually asks Claude Code to do in-session, which may narrow, restate, or (the interesting part) quietly diverge from the spec.
3AI output — what Claude Code actually produces or changes.
4Developer's next step — what the developer does with that output: accepts it, edits it, moves to another file, changes course.

seam A: prompt ↔ spec  ·  seam B: output ↔ prompt  ·  seam C: next-step ↔ any of the above

Observation points, defined precisely

An observation point is the location/mechanism that gives the tool access to a piece of content — not a comparison, and not a tool in its own right. Git-diff, for instance, is a tool; the observation point is "the workspace file tree, watched via VS Code's file-watcher API," which git-diff operates inside of.

Layer Observation point Status
Spec / intent (SPEC.md etc.) VS Code file read/watch on the workspace file Standard, low-risk
Prompt UserPromptSubmit hook — Claude Code's own hook system, HTTP transport ✅ Confirmed directly — §4.6
AI output Stop hook (last_assistant_message) and PostToolUse (structured diffs) ✅ Confirmed directly — §4.6
Developer's own manual next step Independent file-watcher, run by the Observer itself — not anything the hooks expose Only way to observe it — scoped to a future version

Trigger cadence — resolved

A seam-check runs in the background continuously, for each seam, whenever that seam's pair of inputs is available. The flag is surfaced only when "still the same task" evaluates to false — a passing check produces no visible signal at all. For Seam C specifically, the triggering event is defined as: every file save, but only when that save contains an actual code change. The tool's attention is anchored to code changing, not to any timer or idle-detection — no code change, no check.

Re-checking — open, not yet resolved

If a seam passes once, it is not yet decided whether it should be re-checked as the developer continues within what is nominally the same task window. This matters most for Seam C: the Stripe example above shows an early check passing cleanly while drift emerges several edits later, within the same apparent task. Whether Seam C needs continuous re-evaluation across a task's full duration, rather than a single point check, is left open for the next phase.

§4.6 — Resolved: Claude Code observability, confirmed by direct testing

The highest-priority unknown is closed — and the architecture is not a VS Code extension

This was the single highest-priority unknown in the entire concept, and it is no longer a risk: it has been tested directly, in four stages of increasing fidelity (CLI baseline, VS Code surface, HTTP transport, fail-open under a stopped listener), against a real project, with every result independently confirmed rather than assumed. The complete test procedure and raw evidence are preserved in §4.7.

The architecture is not "a VS Code extension observing Claude Code." That was the exact ambiguity left unresolved at the start of this research. It is now clear: the Observer can be a simple CLI tool, usable from within VS Code but not dependent on it. Claude Code has its own official hook system — UserPromptSubmit, Stop, PostToolUse — configured per-project in .claude/settings.json, capable of posting each event as HTTP to a local listener. This works identically from the CLI or the VS Code sidebar — the surface doesn't matter; the hook system is the observation point, and it is surface-agnostic. A VS Code extension, if built later, is one possible front-end for the daemon, not a requirement for it to function.

Seam / layer Hook Confirmed payload
Prompt (Seam A/B input) UserPromptSubmit Verbatim prompt string, plus session/prompt IDs — confirmed on both CLI and VS Code
AI output (Seam B input) Stop last_assistant_message — the AI's final summary text for the turn; field name confirmed exact
AI's own edits — a separate signal, not Seam C PostToolUse Full diff data, in two distinct payload shapes by tool

PostToolUse payloads differ by tool: a Write (new file) carries the full body in tool_input.content; an Edit (existing file) carries tool_input.old_string/new_string plus tool_response.originalFile and tool_response.structuredPatch — a pre-computed, line-numbered unified diff. The Observer never needs to compute its own diff for AI-driven edits; Claude Code already hands over a structured one.

A real Seam C boundary was found — and it is a hard boundary, not a tuning question

PostToolUse and the <ide_opened_file> context tag Claude Code injects are the only two windows into anything the developer does — and both were tested directly against manual developer action (a manually created folder, a manually added file) with zero visibility, across four independent tests, in two different categories of action. The tag is confirmed to be viewport-awareness only ("what file is currently open"), never an action log.

This confirms a real observability gap, not a miscoded definition. Seam C means, and has always meant, AI output vs. the developer's own next step. Nothing the hooks expose can observe that. What the hooks can see is the AI's own edits (via PostToolUse — a genuinely different signal, AI output vs. AI action, useful on its own terms but not a version of Seam C) and the developer's next prompt (a proxy for what happened, not an observation of it). True Seam C would require an independent file-watcher the Observer runs itself, with its own real design questions: what counts as a meaningful manual change, how to avoid noise from routine saves, how to correlate a manual edit back to a task with no prompt to anchor it. That is real work, deliberately scoped to a future version. For MVP, Seam C is not redefined — it is left open, unobservable, and honestly flagged as such, rather than quietly narrowed into something else.

Fail-open is confirmed directly, not inferred

With HTTP hooks genuinely configured and live, the listener process was stopped mid-session and a further prompt was sent. Claude Code continued with no delay, error, or visible degradation. This closes the constitutional requirement stated early in this research — the Observer must never block or interrupt the developer's work, even by malfunctioning — with actual evidence rather than a design intention.

Two further findings worth keeping. A single conversational turn can produce multiple PostToolUse events before the terminating Stop — one turn produced edits across three separate files — so the Observer must treat it as a stream to collect per turn, not a 1:1 event-per-turn assumption. And a 14-minute gap between a prompt and its resulting events, traced to the developer needing to re-authenticate, was ordinary human latency, not a tooling failure; rather than build logic to classify silence, that was explicitly scoped out of v1.

A small, real instance of the tool's own principle

During testing, a malformed settings.json (a leftover comment block, invalid in standard JSON) was silently causing zero hooks to register — an earlier false-negative result was fully explained by this once found. Claude Code was not asked to fix it. It recognized the malformation on its own, unprompted, and — because the file was blocking further work — proactively offered to fix it before anything else could run, flagging that doing so would activate live, HTTP-posting hooks as a real consequence. That is a small, entirely unprompted instance of exactly the kind of noticing this whole tool is trying to build structurally: a system surfacing a consequence before acting, without being asked to.

The next open item is no longer "can this be observed" — it is translating this confirmed hook architecture into the spec, which §4.8 does.

§4.7 — Full test procedure and evidence, in full

The evidence trail, kept rather than summarized

Everything below is the complete evidence behind §4.6, kept in full so this document stays self-contained. N refers to the developer throughout — the person building and testing the Observer. "Fail-open" means: if the observing component breaks or is stopped, the system being observed continues working, unaffected — the Observer's constitution requires this. Stopping the listener is called "stopping," not "killing," deliberately, to match the tool's own philosophy of non-interference.

Why this testing happened: the highest-priority unknown blocking the architecture was whether an external tool could observe an ongoing Claude Code session — N's prompts and Claude Code's outputs — in real time, without controlling or interfering with the session. Rather than assume, it was tested directly.

Test environment: a real working project (magnifica-land), not an empty scaffold — necessary so PostToolUse had real files to act on. Windows, Python 3.11 initially, later 3.14 via PATH adjustment. Two probe implementations in sequence: a file-writing probe for Tests 1a and 1b (command hooks), and an HTTP listener for Test 2 (HTTP hooks).

Test 1a — CLI baseline (command hooks)

Purpose: confirm the plumbing works at all, in the simplest possible configuration, before varying anything else.

Setup: at the project root, .claude/hooks/probe.py was created:

#!/usr/bin/env python3
import sys, json, datetime

raw = sys.stdin.read()
try:
    event = json.loads(raw)
except json.JSONDecodeError:
    event = {"_unparsed": raw}

with open("C:/temp/observer-probe.log", "a") as f:
    f.write(f"=== {datetime.datetime.now().isoformat()} ===\n")
    f.write(f"event: {event.get('hook_event_name')}\n")
    f.write(json.dumps(event, indent=2))
    f.write("\n\n")

sys.exit(0)   # no stdout, no decision — pure observer

.claude/settings.json registered the probe against three events, using exec form (command + args, not shebang execution, since Windows has no chmod):

{
  "hooks": {
    "UserPromptSubmit": [
      { "hooks": [{ "type": "command", "command": "python",
        "args": ["${CLAUDE_PROJECT_DIR}\\.claude\\hooks\\probe.py"] }] }
    ],
    "Stop": [
      { "hooks": [{ "type": "command", "command": "python",
        "args": ["${CLAUDE_PROJECT_DIR}\\.claude\\hooks\\probe.py"] }] }
    ],
    "PostToolUse": [
      { "matcher": "Edit|Write",
        "hooks": [{ "type": "command", "command": "python",
          "args": ["${CLAUDE_PROJECT_DIR}\\.claude\\hooks\\probe.py"] }] }
    ]
  }
}

Result — confirmed green: UserPromptSubmit fired, carrying the verbatim prompt string. PostToolUse fired on Write (file didn't exist yet), carrying tool_input.content — full file body. Stop fired, carrying last_assistant_message. A follow-up run in the same session, editing the now-existing README, confirmed the second payload shape: tool Edit, with old_string/new_string, plus originalFile and structuredPatch.

Findings: Write and Edit produce structurally different payloads. The 14-minute gap noted in §4.6 was observed here, traced to N needing to re-authenticate — human latency, not a tooling failure — leading directly to the v1 scope decision not to classify silence in the event stream.

Test 1b — VS Code surface (command hooks)

Purpose: determine whether the VS Code-integrated surface fires the same hooks as the CLI, since each surface maintains separate session history.

Procedure: log cleared, project opened in VS Code, a prompt sent from the Claude Code sidebar specifically — not the integrated terminal, which would only re-test the CLI.

Result — confirmed green: all three events fired, identical structure to the CLI run. Notably, the UserPromptSubmit payload included an auto-injected tag:

<ide_opened_file>The user opened the file
c:\Development\magnifica-land\.gitignore in the IDE.
This may or may not be related to the current task.</ide_opened_file>
Add a .vscode folder to gitignore.

Follow-up — four targeted tests to find the boundary of this behavior:

  1. 1.gitignore opened in the editor, then prompted → tag appeared, referencing the opened file.
  2. 2README.md opened, then prompted a change → tag appeared again, referencing that file.
  3. 3An empty videos/ folder manually created (no Claude Code involvement), then prompted → no tag, no reference to the manual folder creation anywhere in the prompt context.
  4. 4A real video file manually added into that folder by hand, then a later, unrelated prompt sent → again, no reference anywhere.

Conclusion, confirmed by four consistent results across two categories of action: the <ide_opened_file> injection is viewport/attention awareness only, not an action log. It never surfaces manual file creation or manual edits, under any tested condition — this is the direct evidence behind the Seam C boundary in §4.6.

Test 2 — HTTP transport + fail-open

Purpose: confirm the transport the real Observer daemon actually uses (a localhost HTTP listener, reachable regardless of surface), and confirm the fail-open guarantee under a stopped listener.

Setup: observer_listener.py, standard library only, placed outside the project folder:

#!/usr/bin/env python3
import json
from http.server import BaseHTTPRequestHandler, HTTPServer

class ObserverHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        length = int(self.headers.get("Content-Length", 0))
        raw = self.rfile.read(length).decode("utf-8")
        try:
            event = json.loads(raw)
        except json.JSONDecodeError:
            event = {}

        name = event.get("hook_event_name")
        print("\n" + "─" * 32)
        print(f"EVENT: {name}")
        print(f"session: {event.get('session_id')} | "
              f"prompt_id: {event.get('prompt_id')}")

        if name == "UserPromptSubmit":
            print(f"SEAM A — prompt: {event.get('prompt')!r}")
        elif name == "Stop":
            msg = event.get("last_assistant_message")
            print(f"SEAM B — last_assistant_message: {str(msg)[:400]!r}")
        elif name == "PostToolUse":
            ti = event.get("tool_input", {})
            print(f"tool: {event.get('tool_name')}")
            print(f"  file: {ti.get('file_path')}")
            print(f"  old:  {str(ti.get('old_string'))[:200]!r}")
            print(f"  new:  {str(ti.get('new_string'))[:200]!r}")

        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(b"{}")

    def log_message(self, *a):
        pass

if __name__ == "__main__":
    print("Observer listening on http://localhost:7777")
    HTTPServer(("localhost", 7777), ObserverHandler).serve_forever()

.claude/settings.json was swapped from command to http hooks, each posting to http://localhost:7777/event.

Complication encountered and resolved: the settings file initially contained a leftover //-commented block, invalid in standard JSON, causing Claude Code to report the file as malformed and silently register no hooks at all — this fully explained an earlier false-negative result, initially misread as "HTTP hooks don't fire from VS Code." (This is the incident described in §4.6.)

Result — confirmed green, full seam coverage, multiple turns:

  • Turn 1 (adding video spec info to README): UserPromptSubmitPostToolUse (Edit, README.md) → Stop, all printed correctly, over HTTP, from the VS Code surface.
  • Turn 2 (reverting a change and committing): UserPromptSubmitthree separate PostToolUse events (index.html, styles.css, README.md) → one Stop. Confirmed the stream-not-pairing finding.
  • Manual file addition to videos/ between turns again produced no event and no context injection — a third independent confirmation of the Seam C boundary.

Fail-open check: with the listener running and hooks live, the listener process was stopped (not killed abruptly). A further prompt was sent from the VS Code extension. Claude Code continued normally, with no delay, error, or visible degradation — confirmed directly, with the listener genuinely stopped mid-session and hooks genuinely live via HTTP at the time.

Full v0 checklist — final status

Item Status Evidence
Surface map (CLI vs VS Code)✅ Confirmed identicalTests 1a, 1b
Stop field name✅ Confirmed, exact match1a, 1b, 2
Event ordering✅ Confirmed consistentAll tests
Payload shapes (Write vs Edit)✅ Confirmed, both observedTest 1a
Multiple PostToolUse per turn✅ ConfirmedTest 2, turn 2
Seam C (developer's own actions)✅ Confirmed absent, 4 independent testsTests 1b, 2
HTTP parity with command hooks✅ ConfirmedTest 2
Fail-open under a stopped listener✅ Confirmed directly, live HTTP hooksTest 2
Gap/silence classification⏸ Explicitly deferred, not attempted in v1Test 1a finding

All items originally scoped for v0 are closed with direct evidence.

§4.8 — SPEC.md v1

The constant authority, built directly on the confirmed evidence

This is the actual v1 specification, written directly against the test evidence in §4.7. Per the standing policy in §7, SPEC.md is a constant source of truth for v1, with no exploration-mode toggle — it governs what gets built, not a draft to renegotiate mid-build. Every mechanism claim below traces to a specific confirmed test; no claim rests on documentation alone where a direct test was possible. This is the tool's own principle — faithfulness to what was witnessed, not to what was assumed — applied to its own construction.

What the Observer is, per spec

A local daemon that receives Claude Code hook events in real time, compares observed AI action against the developer's stated intent, and holds an indicator state reflecting whether that intent was faithfully followed. It does not touch code, files, or the development environment. It does not block, delay, or interrupt Claude Code under any circumstance, including its own failure.

The Observer is not a VS Code extension — that framing is fully retired as of this spec. An extension, if built later, is one optional display surface for the daemon's state, not the mechanism of observation.

Architecture

Claude Code (any surface: CLI or VS Code)
        │
        │  HTTP POST — UserPromptSubmit, PostToolUse, Stop
        ▼
Observer daemon (local HTTP listener, Python stdlib or equivalent)
        │
        ├─ holds per-session task-loop state
        ├─ runs seam comparisons against SPEC.md-defined intent
        └─ updates its own indicator state only
        │
        ▼
Display surface (optional, pluggable)
  status bar item · VS Code panel · CLI statusline

Transport is HTTP hooks, confirmed by direct testing to carry full payload parity with command hooks from both CLI and VS Code — this is the v1 product mechanism, not the command-hook file writes used during the test phase itself. The fail-open property is a hard requirement, not an aspiration: any code path that could cause Claude Code to wait on the Observer is a defect, not a limitation to be tolerated.

Hook events used, and what each carries

Only three events are used — deliberately, since the hook system exposes over 20, and the Observer uses the minimum necessary to cover its seams.

UserPromptSubmit → Seam A (intent → prompt)

Carries prompt, the literal string submitted, verbatim. On the VS Code surface a known contamination was confirmed directly: when a file is open in the editor at prompt time, Claude Code prepends an <ide_opened_file> tag to the prompt string itself, with no structural separator — viewport awareness only, never an action record. v1 requirement: the Observer strips <ide_opened_file> tags before treating the remainder as intent. Required only on the VS Code surface; the CLI's prompt field is clean as received.

PostToolUse (matcher: Edit|Write) → AI action

Payload shape branches by tool: Write carries the full body in tool_input.content — no prior state to diff against, inherent to creation, not a gap; Edit carries old/new strings plus originalFile and structuredPatch. v1 requirements: consume structuredPatch directly rather than reconstructing a diff — Claude Code has already computed it, and re-deriving it is unjustified duplicate work — and treat PostToolUse as a stream of zero-or-more events per turn, not a 1:1 pairing with Stop.

A precision corrected from earlier drafts of this spec: PostToolUse gives visibility into AI output → AI action — what Claude Code itself did — a genuinely useful signal, but it is not Seam C and was never meant to be. Seam C's definition does not change: it is, and has only ever been, AI output vs. the developer's own next step. PostToolUse does not observe the developer at all, and nothing here should be read as redefining Seam C to mean something the hooks happen to expose.

Stop → Seam B (prompt → AI output)

Carries last_assistant_message, the complete final AI response text for the turn — field name confirmed exact, repeatedly, across every test run. Stop is used deliberately rather than MessageDisplay, which streams in fragments and has no bearing on the stored transcript; Stop gives the complete, final text once, which is what a seam comparison actually needs.

Event ordering, confirmed reliable across every tested condition:
UserPromptSubmit → PostToolUse (zero or more) → Stop
Held without exception across CLI, VS Code, command hooks, and HTTP hooks, in single- and multi-edit turns.

Disk transcripts — fallback only, never the live path

transcript_path, present on every hook payload, points to Claude Code's own JSONL session log — a format Anthropic's documentation warns is internal and subject to change between versions. v1 requirement: the Observer never reads transcript_path during normal operation. Its only sanctioned use is backfill — recovering seams from before the daemon was running, or after a crash.

The known gap, formalized as a real decision rather than left implicit

Confirmed absent under four independent test conditions: manually opening a file (viewport context only), manually creating a folder, and manually adding a file — none produced any hook event or any trace in later prompt context. This is a structural limit of Claude Code's hook system, not a defect in the Observer's design — no hook fires for anything the developer does that isn't mediated through Claude Code itself.

Option A

Build a genuinely separate VS Code-side observation layer (workspace.onDidChangeTextDocument, file-save watchers), feeding the daemon a second, VS Code-specific event stream.

Option B

Treat the developer's next prompt as an accepted, imperfect proxy for whatever happened in between — the gap collapses into the next loop's Seam A rather than being independently modeled.

This spec does not resolve this choice. It is the one open architectural decision remaining before v1 scope is fully closed, and the build should not proceed against an assumed answer.

Explicitly out of scope for v1

  • ×Gap/silence classification. A gap in the event stream can mean idle/human time, an unmatched tool call, or a hook that fired and failed silently — indistinguishable from the Observer's side. v1 does not attempt to tell them apart; absence of events is recorded as "nothing to compare," never diagnosed. A direct application of faithfulness-over-quality: the tool compares what happened against stated intent, it doesn't investigate why something didn't happen.
  • ×Terminal output parsing. Retired entirely, not merely deprioritized — hooks supersede it.
  • ×Any mechanism that could delay, block, or modify a Claude Code tool call, permission decision, or prompt. The Observer's hooks return exit 0 with no decision payload, or an empty 2xx HTTP body. It has no opinion Claude Code is designed to hear. This is permanent, not a v1 limitation to be lifted later — it follows directly from "witness, not compete for cognition."

On timing — see the correction in §4.5

The tool watches continuously through the session, not only at the end. What it must never do is interrupt. The mechanism that satisfies both is ambient: a single, small flag indicator that appears somewhere in the editor chrome the moment a seam opens, changes nothing else, makes no sound, opens no modal — and reveals its content only when the developer clicks it. The tool does not grade severity or decide how much a given drift matters; it only notices that a seam opened. Whether it is a big deal or a shrug is the developer's judgment to make. Ignoring the flag costs nothing. That is the whole interaction model.

§6 — Product philosophy · the brand DNA piece

The Witness Principle

A first pass, to argue with — not a finished manifesto. Meant to hold up as something to return to across projects, not as ad copy for one product.

Software used to force a kind of honesty. You couldn't write code faster than you could think it. The two were bound together — the pace of typing was the pace of understanding. Every line was a small proof that you knew what you were doing, because you were the one doing it.

AI broke that binding. Not by making developers worse, but by making output outrun understanding. Code can now arrive faster than the thought that should have produced it. Most of the industry's response has been to add more AI to catch what the first AI missed — more agents, more specs, more automated review, more layers of synchronization between what was meant and what was built.

All of it assumes the same thing: that the fix for AI moving too fast for human cognition is more AI in the loop.

We think that's the wrong instinct. Not because AI shouldn't help — it clearly should, and does. But because every tool that inserts itself into the moment of decision is asking for a small piece of authorship. A suggestion accepted is a decision partially outsourced. Do that enough times, in a single session, across a matter of weeks, and the plan that emerges is no longer fully yours — not because anyone took it from you, but because you said yes to enough small things that you lost track of what you were saying yes to.

That's cognitive drift. It isn't a bug in any single tool. It's the compounding cost of a thousand locally-reasonable moments that never added up to anything anyone actually chose.

The fix isn't a smarter participant. It's a witness.

A witness doesn't write. It doesn't suggest. It doesn't optimize, refactor, or offer the next line. It watches what actually happened — the plan you started with, the decisions that followed, the shape the thing has taken — and when you ask, it shows you the difference between the two. Not to correct you. Not to score you. To give you back the one thing every other tool has been quietly spending: your own authorship of what you're building, and why.

This is a deliberate constraint, not a missing feature. AI should witness, not compete for cognition. It should have no opinion on what you build. It should have a very clear opinion on whether you still recognize it.

That distinction — no opinion on the what, a clear opinion on the recognition — is the actual definition of AI is helping you instead of AI is replacing you. Every capability this tool refuses (writing, suggesting, deciding, scoring) is a capability that would have shifted authorship a little further from the developer. Every capability it keeps (watching, comparing, reflecting only when asked) leaves authorship exactly where it was.

It rules in
  • Reflection that is requested, never pushed — the witness speaks when asked, not on a timer or a threshold
  • A record that belongs entirely to the developer — no shared telemetry, no team dashboard by default, no lens anyone else can use to audit you without your say-so
  • Comparison against your own stated intent, not a generic best practice, a style guide, or someone else's architecture
  • Honesty that can be uncomfortable — "here's where this diverged from what you said you were doing" is only useful if it isn't softened into something meaningless
It rules out
  • Real-time suggestions of any kind
  • Auto-fixing, auto-refactoring, or any action that changes the developer's code
  • Scoring, grading, or gamifying the developer's process
  • Making itself the source of truth — the developer's own past words are the source of truth; the tool's job is only to hold up the mirror accurately

Why "witness" and not "assistant," "copilot," or "observer" alone

Language matters here more than usual, because every existing term already carries baggage:

  • "Assistant" / "copilot" implies participation — a second hand on the keyboard. That is precisely the category this tool is defined against.
  • "Observer" is close, and useful as a category word (used that way here), but on its own it is clinical — it describes a mechanism, not a relationship. A security camera observes. A witness testifies to what actually happened.
  • "Witness" carries the right connotations: presence without interference, memory without agenda, and — crucially — a witness is called on. It doesn't volunteer testimony until asked. That is the exact behavioral contract the product should keep.

The name is now decided: AI Observer CLI Tool. This lands close to the reasoning above — "Observer" carries the category correctly, and "CLI Tool" is honest about the confirmed architecture in §4.6: a simple, surface-agnostic CLI daemon, not a VS Code extension. Whether "witness" ever becomes part of the public-facing name, or stays as the verb underneath it — the thing the tool does, quietly, in its documentation and philosophy — is still open, and that distinction is worth keeping regardless of what the name settled on.

§7 — Usage & policy: how authoritative is the spec, and who decides?

A boundary, not a gap: new-but-justified vs. new-but-drifted

Everything in §§1–6 is about mechanism. This section is different in kind — it is about how strictly the tool should be trusted to mean what it reports. A policy question that surfaced directly while working through Seam A's false case, kept distinct from mechanics so the two don't get tangled.

7.1  The question, stated plainly

At what point does a developer have the standing right to explore, trial-and-error, or research something unrelated to the spec — without the tool treating that as drift? And can that standard change mid-session, or must it be fixed for the whole task?

This is not a detection problem. Seam A already does its one job correctly when it reports "no traceable connection between this prompt and SPEC.md." The policy question is what happens after that report — how much weight the developer, or a team, chooses to give it.

7.2  Why the tool cannot answer this on its own — and why that's correct, not a limitation

A seam-check can tell you a prompt has no traceable connection to the spec. It cannot tell you why — because "why" splits into two cases that look identical from the outside:

new-but-justified

The spec was incomplete or didn't anticipate this, and the developer is right to go beyond it.

new-but-drifted

The developer has quietly wandered off the task, one reasonable-seeming step at a time, without meaning to.

Both produce the exact same raw signal: no connection found. The tool has no way to see the developer's reasoning, only their actions and their stated intent — and stated intent, by definition, doesn't cover things the developer hasn't yet said. Trying to make the tool guess which case it is looking at would mean giving it an opinion on the developer's judgment, which is precisely the thing "witness, not participant" rules out. The moment the tool starts deciding whether your reason is good enough, it has stopped witnessing and started managing you.

So this isn't a gap to close later with a smarter model. It is a permanent boundary, for the same reason the tool never grades quality: the tool's only claim is "no connection found." Whether that is a problem is always, unconditionally, the developer's call.

7.3  Where the distinction belongs: not in the tool's logic, in the developer's vocabulary

The distinction is genuinely useful — just not as something the tool computes. It belongs one layer up, as language the developer uses once they are looking at a raw comparison. A few ways it could show up in v1, in order of how soon they are realistic:

  • In documentation / onboarding, immediately. The docs can teach these two terms directly, using something close to the Stripe example: here is what new-but-justified looks like, here is what new-but-drifted looks like, here is why the tool shows the same raw flag for both and leaves the label to you. Costs nothing; can exist from day one.
  • As an optional self-tag on a flag, later. Once a developer sees a raw comparison, a lightweight way to mark it — "justified" or "drifted," their own words if preferred — could exist purely for their own record, never fed back into detection logic, never scored, never shared unless they choose. Needs its own small design pass; not necessary for v1.
  • Never as something the tool decides for you. A standing rule alongside the other non-goals: the tool does not classify a flagged seam as justified or drifted. That judgment stays with the developer, permanently.

7.4  Standing answer, until revisited

SPEC.md is treated as the constant source of truth for the duration of a task, with no built-in "exploration mode" toggle in v1. A seam-check flags any prompt or action with no traceable connection to it, every time, without exception-handling for intent. The developer decides, per flag, whether that is new-but-justified or new-but-drifted — and the documentation should actively teach that vocabulary rather than pretend the tool can make the call. If a more flexible model (an explicit toggle, a declared research window) turns out to be needed once there is real usage, that is a v2 conversation, not a v1 blocker.

§8 — Resolved decisions & remaining open questions

What is settled, and what is honestly still open

Resolved — recorded as decided, not revisited as open
Output format — settled and evolved. Flag content defaults to a raw comparison (spec fragment vs. diff, or prompt vs. output, depending on the seam) with no generated claim attached. A generated one-sentence explanation is available as a secondary, clearly-labeled, user-invoked action ("Explain," visually marked as AI-generated so it is never confused with the raw fact). No score, no metric, no dashboard, no trend line, in either view. This supersedes the earlier "sentence is the default" framing — raw comparison is more consistent with "witness, not participant," since it makes no claim that could itself be wrong.
Faithfulness over quality. The tool measures whether output matched what was asked, never whether it was good. A flawed prompt or next step is not the tool's concern — only whether the developer can trace what happened back to a decision that was actually theirs.
Timing model. Ambient and continuous, never interruptive (§4.5).
Trigger cadence. Background, continuous, per-seam, firing only when a code change has actually occurred (Seam C fires on file save, but only if that save contains a code change — not on every save).
MVP intent source. Whatever the developer provides — .md, .pdf, pasted text, or a prompt typed into the session, in any combination. Nothing more elaborate for v1.
Individual vs. team. Every existing "drift" tool is built for teams and governance. This tool's framing is deeply personal — a developer's relationship to their own cognition, witnessed and reported back only to them. That is the more defensible starting point and the one with less competition. Team or shared-visibility features, if they ever come, should be additive and opt-in — user-controlled, user-generated, and user-owned.
Non-goals — should sit at the top of any future spec. The tool will never modify code, under any circumstance. No severity grading. No team visibility by default. No dashboard, KPI, score, or metric of any kind, in either the raw or the explained view.
Observability — confirmed, not assumed. Claude Code's own hook system (UserPromptSubmit, Stop, PostToolUse), posting HTTP to a local Observer daemon, gives real, tested access to the prompt and the AI's output, regardless of surface. Full evidence in §4.6–§4.7. This was the top-priority unknown and it is closed.
Seam C keeps its original definition — AI output vs. the developer's own next step — and is not observable via hooks alone; now formalized in SPEC.md (§4.8), not papered over. The hook system has zero visibility into manual developer action between AI turns — confirmed four independent times, two methods. PostToolUse exposes a genuinely different, separate signal (AI output → AI action) — useful on its own terms but not a version of Seam C and not a redefinition of it.
Product shape — a CLI-first daemon, not a VS Code extension, now codified in SPEC.md. This resolves the earliest ambiguity in the whole concept: whether the Observer needed to be a VS Code extension. It doesn't. It is a simple CLI tool, usable from within VS Code, with an extension as a possible future display surface.
v1 spec written and locked as constant authority (§4.8). Every mechanism claim traces to a specific confirmed test — the <ide_opened_file> stripping requirement, consuming structuredPatch directly rather than re-deriving diffs, using Stop rather than MessageDisplay, and treating PostToolUse as a stream rather than a 1:1 pairing are settled implementation requirements, not open design questions.
The name is decided: AI Observer CLI Tool. Whether "witness" ever becomes part of the public-facing name, or stays as the verb underneath it, is still open (§6).
Genuinely still open — to return to when this is picked back up
  1. 01Where does the seam-detection comparison mechanism actually live? A Claude API call comparing spec-text to prompt-text to diff, a cheaper embedding-similarity check, or a hybrid (cheap trigger, LLM call only on likely drift) — an implementation question the MVP must answer empirically. Requires researching what tooling/APIs exist; not yet investigated. This is now the top open item, having taken over that position from the now-resolved observability question.
  2. 02Partial-match ambiguity across all three seams. Every worked example is a clean match or clean mismatch. Real sessions produce partial matches (related-but-scope-expanded prompts). Whether that counts as drift, a softer flag, or no flag is undecided.
  3. 03How authoritative is SPEC.md, and can that change mid-session? Addressed in §7. Standing answer: constant authority for v1, no exploration-mode toggle yet. Worth revisiting once there is real usage.
  4. 04Re-checking within a single task window. Whether a seam, once passed, needs continuous re-evaluation as the task continues (the Stripe example, §5), rather than a single point-in-time check. Not yet resolved.
  5. 05False-positive tolerance. A tool that flags too eagerly becomes noise — its own kind of interruption, even if silent. Calibrating how confident a seam-check must be before raising a flag is a real, unresolved tuning problem, likely only answerable empirically once a prototype exists.
  6. 06Recursive validation. If this is built using Claude Code, running the tool against its own development is a natural test — does it actually catch real drift, including the kind already caught once in conversation while building this very document?
  7. 07Gap/silence classification — explicitly deferred, not merely open. Confirmed during testing: a 14-minute gap between a prompt and its resulting events, caused by ordinary re-authentication, was deliberately scoped out of v1 rather than left as an oversight. The Observer does not attempt to interpret silence in the event stream. Recorded here so the deferral is legible as a decision, not a gap in the research.
  8. 08Option A vs. Option B for the developer-action gap — the one open architectural decision remaining before v1 is fully closed. Formalized in SPEC.md (§4.8): either build a genuinely separate VS Code-side observation layer feeding a second event stream, or treat the developer's next prompt as an accepted, imperfect proxy and let the gap collapse into the next loop's Seam A. Do not build against an assumed answer — this needs a deliberate choice before implementation starts.
§9 — One-paragraph summary, for when you need to say it out loud

Cognitive drift is what happens when AI-assisted development lets output outrun understanding — a thousand small, locally-reasonable acceptances that compound into a system nobody actually chose. Every current tool responds by adding another AI to the loop: more specs, more agents, more synchronization. This tool takes the opposite position. It watches a Claude Code session in VS Code — the spec you gave it, the prompt you wrote, what the AI produced, what you did next — and the moment a seam opens between what you meant and what's happening, it shows a quiet flag. Click it, and it tells you in one sentence, not a score: this is where you drifted. Ignore it, and it costs you nothing. It never writes, suggests, or scores. Its only job is to make sure you still recognize what you're building, and why.

AI should witness, not compete for cognition.
Sources

Sources behind the load-bearing claims above, verified against primary material where possible (mid-2026). Figures are attributed to their source and dated; where the evidence is thin or a source could not be independently re-verified in this research pass, that is noted rather than smoothed over.

  1. 1Noda, Storey, Forsgren, Harrison & Houck. "DevEx: What Actually Drives Productivity." Communications of the ACM / ACM Queue (2023; practice ed. Mar 2025). Origin of the three DevEx dimensions — feedback loops, cognitive load, flow state. cacm.acm.org
  2. 2"The Impact of AI Coding Assistants on Software Engineering: A Longitudinal Study." arXiv:2605.23135 (2026). Source for "how AI affects flow state is not well understood," the DevEx-dimension definitions, and the productivity–experience paradox (84% / 14%→27%). arxiv.org/html/2605.23135v1
  3. 3"EditFlow: Benchmarking and Optimizing Code Edit Recommendation Systems via Reconstruction of Developer Flows." arXiv:2602.21697 (2026). Source for the interruption-pattern quote and the finding that a 10% interruption rate can nearly double task-completion time (citing prior interruption-cost literature). arxiv.org/pdf/2602.21697
  4. 4"Black box AI drift: AI tools are making design decisions nobody asked for." Stack Overflow Blog, 23 Apr 2026. The closest conceptual neighbor — tool-side, not developer-side. stackoverflow.blog
  5. 5Stillwell, J. "Intent-Driven Development." Zero, but True, 10 Mar 2026. The Decision-Layer model and its own admission that incremental changes accumulate drift. jason-stillwell.com
  6. 6Packmind. "Context Engineering Best Practices for AI-Powered Dev Teams (2026)." Source for the ContextOps "automated drift detection, pre-commit enforcement, cross-file consistency checks" framing. packmind.com
  7. 7Tricentis. "Intent Drift in AI Code: Fix Regression Blind Spots," 1 May 2026. Source for intent drift as "a silent failure mode … where behavior gradually diverges from specification without necessarily breaking a test or failing a pipeline." tricentis.com
  8. 8Augment Code. "Intent" — spec-driven, multi-agent development with a "living spec" and reviewer agents that make drift "visible and fixable" on every modification. augmentcode.com
  9. 9Human–AI collaboration design study (the "Idy" autonomous-agent reactions and the inspiration-archival "user-controlled, user-generated, user-owned" quotes). Carried over from the author's earlier research corpus and not independently re-verified in this research pass — treat the specific quotations as author-sourced pending a citation. The underlying pattern (designer discomfort with autonomous mid-task AI; demand for user-owned material) is corroborated by adjacent human-AI collaboration literature.

Note on the "SmartBear / Swagger" mention (§3.1): stated from general knowledge of the API-spec tooling market and not tied to a specific dated source in this pass.