[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6G2GWAC4637ENKMSBNKQ5MP":3,"skill-same:01M6G2GWAC4637ENKMSBNKQ5MP":65},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":36,"linkOnly":37,"markdownContent":38,"markdownBody":39,"frontMatter":40,"refName":42,"commitSha":43,"skillDirectory":44,"forksCount":45,"repositoryHtmlUrl":46,"repositoryHomepageUrl":6,"ownerHtmlUrl":47,"ownerBlogUrl":48,"ownerDescription":49,"updatedAt":50,"install":51,"resources":64},"01M6G2GWAC4637ENKMSBNKQ5MP","content-hash-cache-pattern",null,"Cache expensive file processing results using SHA-256 content hashes — path-independent, auto-invalidating, with service layer separation.","oabdelmaksoud\u002FAgention","oabdelmaksoud","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F50699149?v=4","01M6D5CVVN778ZCDP1WHS816SP","Omar Abdelmaksoud","01M6D8A4TE76V3DCSH3D94VG1V",2,"MIT","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fcontent-hash-cache-pattern\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[24,25,26,27,28,29,30,31,32,33,34,35],"content","cache","pattern","content hash cache pattern","file","sha-256","results","auto","service","processing","separation","with","2026-11-10 10:12:30",false,"---\nname: content-hash-cache-pattern\ndescription: Cache expensive file processing results using SHA-256 content hashes — path-independent, auto-invalidating, with service layer separation.\norigin: ECC\n---\n\n# Content-Hash File Cache Pattern\n\nCache 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\u002Frenames and auto-invalidates when content changes.\n\n## When to Activate\n\n- Building file processing pipelines (PDF, images, text extraction)\n- Processing cost is high and same files are processed repeatedly\n- Need a `--cache\u002F--no-cache` CLI option\n- Want to add caching to existing pure functions without modifying them\n\n## Core Pattern\n\n### 1. Content-Hash Based Cache Key\n\nUse file content (not path) as the cache key:\n\n```python\nimport hashlib\nfrom pathlib import Path\n\n_HASH_CHUNK_SIZE = 65536  # 64KB chunks for large files\n\ndef compute_file_hash(path: Path) -> str:\n    \"\"\"SHA-256 of file contents (chunked for large files).\"\"\"\n    if not path.is_file():\n        raise FileNotFoundError(f\"File not found: {path}\")\n    sha256 = hashlib.sha256()\n    with open(path, \"rb\") as f:\n        while True:\n            chunk = f.read(_HASH_CHUNK_SIZE)\n            if not chunk:\n                break\n            sha256.update(chunk)\n    return sha256.hexdigest()\n```\n\n**Why content hash?** File rename\u002Fmove = cache hit. Content change = automatic invalidation. No index file needed.\n\n### 2. Frozen Dataclass for Cache Entry\n\n```python\nfrom dataclasses import dataclass\n\n@dataclass(frozen=True, slots=True)\nclass CacheEntry:\n    file_hash: str\n    source_path: str\n    document: ExtractedDocument  # The cached result\n```\n\n### 3. File-Based Cache Storage\n\nEach cache entry is stored as `{hash}.json` — O(1) lookup by hash, no index file required.\n\n```python\nimport json\nfrom typing import Any\n\ndef write_cache(cache_dir: Path, entry: CacheEntry) -> None:\n    cache_dir.mkdir(parents=True, exist_ok=True)\n    cache_file = cache_dir \u002F f\"{entry.file_hash}.json\"\n    data = serialize_entry(entry)\n    cache_file.write_text(json.dumps(data, ensure_ascii=False), encoding=\"utf-8\")\n\ndef read_cache(cache_dir: Path, file_hash: str) -> CacheEntry | None:\n    cache_file = cache_dir \u002F f\"{file_hash}.json\"\n    if not cache_file.is_file():\n        return None\n    try:\n        raw = cache_file.read_text(encoding=\"utf-8\")\n        data = json.loads(raw)\n        return deserialize_entry(data)\n    except (json.JSONDecodeError, ValueError, KeyError):\n        return None  # Treat corruption as cache miss\n```\n\n### 4. Service Layer Wrapper (SRP)\n\nKeep the processing function pure. Add caching as a separate service layer.\n\n```python\ndef extract_with_cache(\n    file_path: Path,\n    *,\n    cache_enabled: bool = True,\n    cache_dir: Path = Path(\".cache\"),\n) -> ExtractedDocument:\n    \"\"\"Service layer: cache check -> extraction -> cache write.\"\"\"\n    if not cache_enabled:\n        return extract_text(file_path)  # Pure function, no cache knowledge\n\n    file_hash = compute_file_hash(file_path)\n\n    # Check cache\n    cached = read_cache(cache_dir, file_hash)\n    if cached is not None:\n        logger.info(\"Cache hit: %s (hash=%s)\", file_path.name, file_hash[:12])\n        return cached.document\n\n    # Cache miss -> extract -> store\n    logger.info(\"Cache miss: %s (hash=%s)\", file_path.name, file_hash[:12])\n    doc = extract_text(file_path)\n    entry = CacheEntry(file_hash=file_hash, source_path=str(file_path), document=doc)\n    write_cache(cache_dir, entry)\n    return doc\n```\n\n## Key Design Decisions\n\n| Decision | Rationale |\n|----------|-----------|\n| SHA-256 content hash | Path-independent, auto-invalidates on content change |\n| `{hash}.json` file naming | O(1) lookup, no index file needed |\n| Service layer wrapper | SRP: extraction stays pure, cache is a separate concern |\n| Manual JSON serialization | Full control over frozen dataclass serialization |\n| Corruption returns `None` | Graceful degradation, re-processes on next run |\n| `cache_dir.mkdir(parents=True)` | Lazy directory creation on first write |\n\n## Best Practices\n\n- **Hash content, not paths** — paths change, content identity doesn't\n- **Chunk large files** when hashing — avoid loading entire files into memory\n- **Keep processing functions pure** — they should know nothing about caching\n- **Log cache hit\u002Fmiss** with truncated hashes for debugging\n- **Handle corruption gracefully** — treat invalid cache entries as misses, never crash\n\n## Anti-Patterns to Avoid\n\n```python\n# BAD: Path-based caching (breaks on file move\u002Frename)\ncache = {\"\u002Fpath\u002Fto\u002Ffile.pdf\": result}\n\n# BAD: Adding cache logic inside the processing function (SRP violation)\ndef extract_text(path, *, cache_enabled=False, cache_dir=None):\n    if cache_enabled:  # Now this function has two responsibilities\n        ...\n\n# BAD: Using dataclasses.asdict() with nested frozen dataclasses\n# (can cause issues with complex nested types)\ndata = dataclasses.asdict(entry)  # Use manual serialization instead\n```\n\n## When to Use\n\n- File processing pipelines (PDF parsing, OCR, text extraction, image analysis)\n- CLI tools that benefit from `--cache\u002F--no-cache` options\n- Batch processing where the same files appear across runs\n- Adding caching to existing pure functions without modifying them\n\n## When NOT to Use\n\n- Data that must always be fresh (real-time feeds)\n- Cache entries that would be extremely large (consider streaming instead)\n- Results that depend on parameters beyond file content (e.g., different extraction configs)\n","# Content-Hash File Cache Pattern\n\nCache 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\u002Frenames and auto-invalidates when content changes.\n\n## When to Activate\n\n- Building file processing pipelines (PDF, images, text extraction)\n- Processing cost is high and same files are processed repeatedly\n- Need a `--cache\u002F--no-cache` CLI option\n- Want to add caching to existing pure functions without modifying them\n\n## Core Pattern\n\n### 1. Content-Hash Based Cache Key\n\nUse file content (not path) as the cache key:\n\n```python\nimport hashlib\nfrom pathlib import Path\n\n_HASH_CHUNK_SIZE = 65536  # 64KB chunks for large files\n\ndef compute_file_hash(path: Path) -> str:\n    \"\"\"SHA-256 of file contents (chunked for large files).\"\"\"\n    if not path.is_file():\n        raise FileNotFoundError(f\"File not found: {path}\")\n    sha256 = hashlib.sha256()\n    with open(path, \"rb\") as f:\n        while True:\n            chunk = f.read(_HASH_CHUNK_SIZE)\n            if not chunk:\n                break\n            sha256.update(chunk)\n    return sha256.hexdigest()\n```\n\n**Why content hash?** File rename\u002Fmove = cache hit. Content change = automatic invalidation. No index file needed.\n\n### 2. Frozen Dataclass for Cache Entry\n\n```python\nfrom dataclasses import dataclass\n\n@dataclass(frozen=True, slots=True)\nclass CacheEntry:\n    file_hash: str\n    source_path: str\n    document: ExtractedDocument  # The cached result\n```\n\n### 3. File-Based Cache Storage\n\nEach cache entry is stored as `{hash}.json` — O(1) lookup by hash, no index file required.\n\n```python\nimport json\nfrom typing import Any\n\ndef write_cache(cache_dir: Path, entry: CacheEntry) -> None:\n    cache_dir.mkdir(parents=True, exist_ok=True)\n    cache_file = cache_dir \u002F f\"{entry.file_hash}.json\"\n    data = serialize_entry(entry)\n    cache_file.write_text(json.dumps(data, ensure_ascii=False), encoding=\"utf-8\")\n\ndef read_cache(cache_dir: Path, file_hash: str) -> CacheEntry | None:\n    cache_file = cache_dir \u002F f\"{file_hash}.json\"\n    if not cache_file.is_file():\n        return None\n    try:\n        raw = cache_file.read_text(encoding=\"utf-8\")\n        data = json.loads(raw)\n        return deserialize_entry(data)\n    except (json.JSONDecodeError, ValueError, KeyError):\n        return None  # Treat corruption as cache miss\n```\n\n### 4. Service Layer Wrapper (SRP)\n\nKeep the processing function pure. Add caching as a separate service layer.\n\n```python\ndef extract_with_cache(\n    file_path: Path,\n    *,\n    cache_enabled: bool = True,\n    cache_dir: Path = Path(\".cache\"),\n) -> ExtractedDocument:\n    \"\"\"Service layer: cache check -> extraction -> cache write.\"\"\"\n    if not cache_enabled:\n        return extract_text(file_path)  # Pure function, no cache knowledge\n\n    file_hash = compute_file_hash(file_path)\n\n    # Check cache\n    cached = read_cache(cache_dir, file_hash)\n    if cached is not None:\n        logger.info(\"Cache hit: %s (hash=%s)\", file_path.name, file_hash[:12])\n        return cached.document\n\n    # Cache miss -> extract -> store\n    logger.info(\"Cache miss: %s (hash=%s)\", file_path.name, file_hash[:12])\n    doc = extract_text(file_path)\n    entry = CacheEntry(file_hash=file_hash, source_path=str(file_path), document=doc)\n    write_cache(cache_dir, entry)\n    return doc\n```\n\n## Key Design Decisions\n\n| Decision | Rationale |\n|----------|-----------|\n| SHA-256 content hash | Path-independent, auto-invalidates on content change |\n| `{hash}.json` file naming | O(1) lookup, no index file needed |\n| Service layer wrapper | SRP: extraction stays pure, cache is a separate concern |\n| Manual JSON serialization | Full control over frozen dataclass serialization |\n| Corruption returns `None` | Graceful degradation, re-processes on next run |\n| `cache_dir.mkdir(parents=True)` | Lazy directory creation on first write |\n\n## Best Practices\n\n- **Hash content, not paths** — paths change, content identity doesn't\n- **Chunk large files** when hashing — avoid loading entire files into memory\n- **Keep processing functions pure** — they should know nothing about caching\n- **Log cache hit\u002Fmiss** with truncated hashes for debugging\n- **Handle corruption gracefully** — treat invalid cache entries as misses, never crash\n\n## Anti-Patterns to Avoid\n\n```python\n# BAD: Path-based caching (breaks on file move\u002Frename)\ncache = {\"\u002Fpath\u002Fto\u002Ffile.pdf\": result}\n\n# BAD: Adding cache logic inside the processing function (SRP violation)\ndef extract_text(path, *, cache_enabled=False, cache_dir=None):\n    if cache_enabled:  # Now this function has two responsibilities\n        ...\n\n# BAD: Using dataclasses.asdict() with nested frozen dataclasses\n# (can cause issues with complex nested types)\ndata = dataclasses.asdict(entry)  # Use manual serialization instead\n```\n\n## When to Use\n\n- File processing pipelines (PDF parsing, OCR, text extraction, image analysis)\n- CLI tools that benefit from `--cache\u002F--no-cache` options\n- Batch processing where the same files appear across runs\n- Adding caching to existing pure functions without modifying them\n\n## When NOT to Use\n\n- Data that must always be fresh (real-time feeds)\n- Cache entries that would be extremely large (consider streaming instead)\n- Results that depend on parameters beyond file content (e.g., different extraction configs)\n",{"name":5,"origin":41,"description":7},"ECC","main","a318f48de3c5718e8ea2e9f6fae7790e8a759e85","upstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fcontent-hash-cache-pattern",0,"https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fo-abdelmaksoud\u002F","Full-Stack Engineer | AI Systems Architect | Building autonomous multi-agent systems","2026-03-08 21:23:03",{"source":8,"skillName":5,"commands":52,"prompt":62,"zipAvailable":63},[53,56,59],{"tool":54,"command":55},"npx","npx skills add oabdelmaksoud\u002FAgention --skill content-hash-cache-pattern",{"tool":57,"command":58},"bunx","bunx skills add oabdelmaksoud\u002FAgention --skill content-hash-cache-pattern",{"tool":60,"command":61},"pnpm","pnpm dlx skills add oabdelmaksoud\u002FAgention --skill content-hash-cache-pattern","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fcontent-hash-cache-pattern\u002FSKILL.md",true,[],[66,89,103,134,160,179],{"skillNo":67,"name":68,"nameZh":6,"description":69,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":70,"categories":71,"keywords":77,"publishedAt":36},"01M6G2QFCBNBYAJF2KTK85G9A6","visa-doc-translate","Translate visa application documents (images) to English and create a bilingual PDF with original and translation","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fvisa-doc-translate\u002FSKILL.md",[72],{"categoryNo":73,"categoryName":74,"taxonomyType":75,"taxonomyTypeDesc":76},"01JBSEEDCAT000000000000002","文档处理","SCENARIO","使用场景",[78,79,80,81,35,82,83,84,85,86,87,88],"translate","doc","visa doc translate","bilingual","english","application","PDF","translation","documents","create","images",{"skillNo":90,"name":91,"nameZh":6,"description":92,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":36},"01M6G2QB09TSK6BY4ME5X20EVQ","verification-loop","A comprehensive verification system for Claude Code sessions.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fverification-loop\u002FSKILL.md",[],[96,97,98,99,100,101,102],"verification","loop","verification loop","sessions","code","claude code sessions","system",{"skillNo":104,"name":105,"nameZh":6,"description":106,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":118,"publishedAt":36},"01M6G2Q6V2F7G03VAAF27FXPJR","tdd-workflow","Use this skill when writing new features, fixing bugs, or refactoring code. Enforces test-driven development with 80%+ coverage including unit, integration, and E2E tests.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Ftdd-workflow\u002FSKILL.md",[109,112,115],{"categoryNo":110,"categoryName":111,"taxonomyType":75,"taxonomyTypeDesc":76},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":113,"categoryName":114,"taxonomyType":75,"taxonomyTypeDesc":76},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":116,"categoryName":117,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000030","开发工程师",[119,120,121,122,123,124,125,126,127,100,128,129,130,131,35,132,133],"workflow","tdd","tdd workflow","use","unit","coverage","refactoring","e2e","integration","development","e2e tests","tests","driven","test","writing",{"skillNo":135,"name":136,"nameZh":6,"description":137,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":138,"categories":139,"keywords":140,"publishedAt":36},"01M6G2Q359YJRWAR2PFCEQAXF3","swiftui-patterns","SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS\u002FmacOS UI best practices.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswiftui-patterns\u002FSKILL.md",[],[141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,35],"patterns","swiftui","swiftui patterns","architecture","macos","performance","state management","best practices","state","ui","Optimization","ios","architecture patterns","Composition","performance optimization","view","management","swiftui architecture","navigation",{"skillNo":161,"name":162,"nameZh":6,"description":163,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":164,"categories":165,"keywords":167,"publishedAt":36},"01M6G2PY8B2FWZTWPZ84H83Y7C","swift-protocol-di-testing","Protocol-based dependency injection for testable Swift code — mock file system, network, and external APIs using focused protocols and Swift Testing.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-protocol-di-testing\u002FSKILL.md",[166],{"categoryNo":110,"categoryName":111,"taxonomyType":75,"taxonomyTypeDesc":76},[168,169,170,171,100,172,28,173,174,102,175,176,177,178],"swift protocol di testing","protocol","swift","testing","protocols","network","injection","dependency","swift testing","dependency injection","mock",{"skillNo":180,"name":181,"nameZh":6,"description":182,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":183,"categories":184,"keywords":185,"publishedAt":36},"01M6G2PSCN2GXV9FFZDRRRWVB6","swift-concurrency-6-2","Swift 6.2 Approachable Concurrency — single-threaded by default, @concurrent for explicit background offloading, isolated conformances for main actor types.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-concurrency-6-2\u002FSKILL.md",[],[186,187,188,170,189,42,190],"concurrency","swift concurrency","swift concurrency 6 2","default","types"]