Skip repeat reads of an unchanged file in a Claude Code mod
The core of reread-guard. A Read of the same file and range is denied while its size and mtime are unchanged; an immediate retry still goes through, because Claude Code can clear old tool results from context. The full mod also scopes this per subagent and resets on /compact and /clear.
import type { Register } from 'claude-code'
export const register: Register = on => {
const seen = new Map<string, { size: number; mtimeMs: number }>()
const skippedOnce = new Set<string>()
on('tool.call', { tool: 'Read' }, async ($, e, next) => {
const stat = await $.fs.stat(e.file_path, { resolve: true }).catch(() => undefined)
if (!stat || stat.kind !== 'file') return next(e)
const key = [e.file_path.toLowerCase(), e.offset ?? '', e.limit ?? ''].join('|')
const before = seen.get(key)
const unchanged = before?.size === stat.size && before?.mtimeMs === stat.mtimeMs
if (unchanged && !skippedOnce.has(key)) {
skippedOnce.add(key)
// Short on purpose: the model reads it.
return { deny: 'File unchanged since you read it; use that copy. If it is gone from context, retry the same Read.' }
}
skippedOnce.delete(key)
seen.set(key, { size: stat.size, mtimeMs: stat.mtimeMs })
const ran = await next(e)
if (ran.deny !== undefined || ran.isError === true) seen.delete(key)
return ran
})
}