Diagnostics file and hook protocol
These formats are how agents and scripts talk to OpenFiles. They are versioned; breaking changes bump version.
.openfiles/diagnostics.json
Section titled “.openfiles/diagnostics.json”Written by the extension, in each workspace folder, whenever problems in AI-edited files change.
{ "version": 1, "updatedAt": 1789322228723, // epoch ms "hook": { "feedback": "errorsAndWarnings", // openfiles.hooks.feedback "timeoutMs": 4000 // openfiles.hooks.feedbackTimeoutMs }, "files": { "src/auth.ts": { // workspace-relative, forward slashes "path": "/home/me/app/src/auth.ts", "checkedAt": 1789322228700, // when diagnostics settled after the last edit; 0 = not yet "errors": 1, "warnings": 0, "items": [ { "line": 42, // 1-based "column": 7, // 1-based "severity": "error", // error | warning | info | hint "source": "ts", "code": "2322", "message": "Type 'string' is not assignable to type 'number'." } ] } }}Reading it from an agent:
- Only files changed in the current session are listed.
- If
checkedAtis older than your edit, the editor hasn’t finished checking yet. Wait and read again. - In
queuemode files aren’t opened, so many language servers won’t have looked at them. An emptyitemsthere doesn’t mean clean.
.openfiles/queue.jsonl
Section titled “.openfiles/queue.jsonl”Appended by hook.js, one JSON object per line. The extension reads new lines and truncates the file once it has read everything.
{"v":1,"ts":1789322228384,"agent":"claude","tool":"Edit","paths":["/home/me/app/src/auth.ts"]}Anything can write here: a script, a Makefile, another tool. Use absolute paths.
hook.js
Section titled “hook.js”node ~/.openfiles/hook.js --agent <id> [--event <name>] [--no-feedback]| Argument | |
|---|---|
--agent |
claude, codex, copilot, vscode, gemini, qwen, kimi, cursor, windsurf, kiro, cline, droid, goose, opencode, unknown |
--event |
the hook event, when an agent has several (afterFileEdit, postToolUse) |
--no-feedback |
only report the edit; don’t wait for or print diagnostics |
Behavior:
- Reads the hook payload from stdin (3 s max).
- Finds edited paths. Tools whose name doesn’t look like a write (
Read,Grep,Bash) are ignored. - Walks up from the edited file to the nearest folder with a fresh
.openfiles/vscode/*.json(less than 60 s old). If there isn’t one, it exits. - Appends to
queue.jsonl. - Unless
--no-feedbackis set, it waits until every path hascheckedAt ≥the time of step 4, or untilhook.timeoutMspasses. - Prints feedback in the agent’s format, or nothing:
| Agent | Output |
|---|---|
| claude, codex, qwen, kimi, droid | {"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"…"}} |
| gemini | {"hookSpecificOutput":{"hookEventName":"AfterTool","additionalContext":"…"}} |
| copilot, vscode | {"additionalContext":"…","hookSpecificOutput":{…}} |
cursor (postToolUse) |
{"additional_context":"…"} |
| everyone else | nothing |
It always exits 0.
.openfiles/vscode/<id>.json
Section titled “.openfiles/vscode/<id>.json”One file per VS Code window, refreshed every openfiles.heartbeatSeconds. It’s useful if an agent wants to know what you’re looking at.
{ "version": 1, "workspaceRoot": "/home/me/app", "sessionId": "…", "appName": "Visual Studio Code", "updatedAt": 1789322228.72, "files": ["/home/me/app/src/auth.ts"]}updatedAt is in seconds, kept that way for compatibility with 0.1 clients.