Drop the 24h TTL: HTTP validators are the whole freshness contract.
Key cache on URL alone; prompt-aware keying with normalization gave
false safety (semantic differences slipped through). Prompt is kept
as metadata and surfaced in the hit message so the next agent can
judge whether the earlier reading applies. Reframe docs around
"HTTP resource cache, not prompt cache".
While here, fix two latent bugs:
- Replace the unquoted heredoc in the pre-hook with printf. The
heredoc expanded $vars and backticks inside cached content, so a
compromised doc page could trigger command substitution on cache
hit.
- Strip CR before awk paragraph-mode parsing of curl -I -L output
so blank separators between response blocks on a redirect chain
are recognised (was silently picking intermediate headers).
Remove dead -v IGNORECASE=1 (gawk-only; tolower() already handles it).
Adds a pair of optional Claude Code hooks that cache WebFetch output
on disk but revalidate every reuse against the origin. Content is
served only when the server returns 304 Not Modified, so
source-driven-development's "verify against current docs" guarantee
still holds across sessions.
- hooks/sdd-cache-pre.sh: PreToolUse hook. For a cached entry, issues
a HEAD with If-None-Match / If-Modified-Since. On 304, blocks the
WebFetch (exit 2) and returns cached content via stderr; otherwise
allows the fetch through.
- hooks/sdd-cache-post.sh: PostToolUse hook. Captures response plus
current ETag / Last-Modified. Entries without a validator are
never stored — without one, the pre hook cannot verify freshness
and caching would amount to trusting memory.
- Cache key: sha256(url + normalized_prompt). Prompt is lowercased
and whitespace-collapsed so stylistic variants hit the same entry;
semantically different prompts still miss.
- Hard 24h TTL as a safety net against misbehaving origins.
- hooks/SDD-CACHE.md: opt-in setup, end-to-end testing, debugging.
- .gitignore: ignore the .claude/sdd-cache/ directory.
Hooks are opt-in: users register them in .claude/settings.json. The
source-driven-development skill itself is unchanged.