Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
affaan-m avatar

Content Hash Cache Pattern

  • 1.4k installs
  • 238k repo stars
  • Updated August 5, 2026
  • affaan-m/ecc

This is a copy of content-hash-cache-pattern by affaan-m - installs and ranking accrue to the original listing.

content-hash-cache-pattern is a Claude Code skill that caches expensive file-processing results using SHA-256 content hashes for developers who need path-independent, auto-invalidating caches in PDF and image pipelines.

About

content-hash-cache-pattern is an ECC skill for caching expensive file processing—PDF parsing, text extraction, image analysis—using SHA-256 content hashes as cache keys instead of file paths. Keys survive renames and moves and auto-invalidate when file bytes change. The pattern separates cache logic into a service layer and supports --cache/--no-cache CLI toggles. Developers reach for content-hash-cache-pattern when pipelines reprocess the same documents, processing cost is high, or agents add caching to file-ingestion tools. Unlike path-based caches, hash keys prevent stale hits after content edits even when filenames stay the same. Use it while building ingestion CLIs, document AI preprocessors, or batch analyzers.

  • Uses SHA-256 content hashes as cache keys instead of file paths
  • Survives file moves and renames while auto-invalidating on content changes
  • Service-layer separation keeps pure functions untouched
  • Built-in support for --cache/--no-cache CLI options
  • Chunked 64KB reading optimized for large files

Content Hash Cache Pattern by the numbers

  • 1,383 all-time installs (skills.sh)
  • +82 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/affaan-m/ecc --skill content-hash-cache-pattern

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs1.4k
repo stars238k
Last updatedAugust 5, 2026
Repositoryaffaan-m/ecc

How do you cache file processing by content hash?

Cache expensive file-processing results like PDF parsing or image analysis without re-running the same content repeatedly.

Who is it for?

Backend developers building PDF, image, or text extraction pipelines where repeated processing is costly and files may move or rename.

Skip if: Simple HTTP response caching or workloads where file paths never change and content never updates.

When should I use this skill?

The user builds file processing pipelines, adds --cache flags, or needs path-independent invalidation for PDF or image analysis.

What you get

SHA-256 keyed cache layer with service separation and CLI cache toggle for file pipelines

  • Content-hash cache service layer
  • CLI with --cache/--no-cache toggle

By the numbers

  • Uses SHA-256 content hashes as path-independent cache keys

Files

SKILL.mdMarkdownGitHub ↗

Content-Hash File Cache Pattern

Cache expensive file processing results (PDF parsing, text extraction, image analysis) using SHA-256 content hashes as cache keys. Unlike path-based caching, this approach survives file moves/renames and auto-invalidates when content changes.

When to Activate

  • Building file processing pipelines (PDF, images, text extraction)
  • Processing cost is high and same files are processed repeatedly
  • Need a --cache/--no-cache CLI option
  • Want to add caching to existing pure functions without modifying them

Core Pattern

1. Content-Hash-Based Cache Key

Use file content (not path) as the cache key:

import hashlib
from pathlib import Path

_HASH_CHUNK_SIZE = 65536  # 64KB chunks for large files

def compute_file_hash(path: Path) -> str:
    """SHA-256 of file contents (chunked for large files)."""
    if not path.is_file():
        raise FileNotFoundError(f"File not found: {path}")
    sha256 = hashlib.sha256()
    with open(path, "rb") as f:
        while True:
            chunk = f.read(_HASH_CHUNK_SIZE)
            if not chunk:
                break
            sha256.update(chunk)
    return sha256.hexdigest()

Why content hash? File rename/move = cache hit. Content change = automatic invalidation. No index file needed.

2. Frozen Dataclass for Cache Entry

from dataclasses import dataclass

@dataclass(frozen=True, slots=True)
class CacheEntry:
    file_hash: str
    source_path: str
    document: ExtractedDocument  # The cached result

3. File-Based Cache Storage

Each cache entry is stored as {hash}.json — O(1) lookup by hash, no index file required.

import json
from typing import Any

def write_cache(cache_dir: Path, entry: CacheEntry) -> None:
    cache_dir.mkdir(parents=True, exist_ok=True)
    cache_file = cache_dir / f"{entry.file_hash}.json"
    data = serialize_entry(entry)
    cache_file.write_text(json.dumps(data, ensure_ascii=False), encoding="utf-8")

def read_cache(cache_dir: Path, file_hash: str) -> CacheEntry | None:
    cache_file = cache_dir / f"{file_hash}.json"
    if not cache_file.is_file():
        return None
    try:
        raw = cache_file.read_text(encoding="utf-8")
        data = json.loads(raw)
        return deserialize_entry(data)
    except (json.JSONDecodeError, ValueError, KeyError):
        return None  # Treat corruption as cache miss

4. Service Layer Wrapper (SRP)

Keep the processing function pure. Add caching as a separate service layer.

def extract_with_cache(
    file_path: Path,
    *,
    cache_enabled: bool = True,
    cache_dir: Path = Path(".cache"),
) -> ExtractedDocument:
    """Service layer: cache check -> extraction -> cache write."""
    if not cache_enabled:
        return extract_text(file_path)  # Pure function, no cache knowledge

    file_hash = compute_file_hash(file_path)

    # Check cache
    cached = read_cache(cache_dir, file_hash)
    if cached is not None:
        logger.info("Cache hit: %s (hash=%s)", file_path.name, file_hash[:12])
        return cached.document

    # Cache miss -> extract -> store
    logger.info("Cache miss: %s (hash=%s)", file_path.name, file_hash[:12])
    doc = extract_text(file_path)
    entry = CacheEntry(file_hash=file_hash, source_path=str(file_path), document=doc)
    write_cache(cache_dir, entry)
    return doc

Key Design Decisions

DecisionRationale
SHA-256 content hashPath-independent, auto-invalidates on content change
{hash}.json file namingO(1) lookup, no index file needed
Service layer wrapperSRP: extraction stays pure, cache is a separate concern
Manual JSON serializationFull control over frozen dataclass serialization
Corruption returns NoneGraceful degradation, re-processes on next run
cache_dir.mkdir(parents=True)Lazy directory creation on first write

Best Practices

  • Hash content, not paths — paths change, content identity doesn't
  • Chunk large files when hashing — avoid loading entire files into memory
  • Keep processing functions pure — they should know nothing about caching
  • Log cache hit/miss with truncated hashes for debugging
  • Handle corruption gracefully — treat invalid cache entries as misses, never crash

Anti-Patterns to Avoid

# BAD: Path-based caching (breaks on file move/rename)
cache = {"/path/to/file.pdf": result}

# BAD: Adding cache logic inside the processing function (SRP violation)
def extract_text(path, *, cache_enabled=False, cache_dir=None):
    if cache_enabled:  # Now this function has two responsibilities
        ...

# BAD: Using dataclasses.asdict() with nested frozen dataclasses
# (can cause issues with complex nested types)
data = dataclasses.asdict(entry)  # Use manual serialization instead

When to Use

  • File processing pipelines (PDF parsing, OCR, text extraction, image analysis)
  • CLI tools that benefit from --cache/--no-cache options
  • Batch processing where the same files appear across runs
  • Adding caching to existing pure functions without modifying them

When NOT to Use

  • Data that must always be fresh (real-time feeds)
  • Cache entries that would be extremely large (consider streaming instead)
  • Results that depend on parameters beyond file content (e.g., different extraction configs)

Related skills

How it compares

Pick content-hash-cache-pattern over path-based memoization when files rename often or content edits must invalidate cached PDF and image results.

FAQ

Why use content-hash caching over path keys?

content-hash-cache-pattern keys caches with SHA-256 digests of file bytes, so results stay valid after renames and invalidate automatically when content changes. Path-based keys can return stale data after edits or break when files move.

What workloads fit content-hash-cache-pattern?

content-hash-cache-pattern fits expensive file pipelines—PDF parsing, text extraction, image analysis—where the same content is processed repeatedly. The pattern adds service-layer caching and optional --cache/--no-cache CLI controls for ingestion tools.

Automation & Workflowsbackendintegrations

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.