Datasheets Skill Purpose Extract structured, machine-readable specifications from component datasheet PDFs and make them available to analyzer skills. Works on whatever PDFs are downloaded under (downloads are owned by distributor skills like , , , ). Scope This skill owns: - Extraction schema — the canonical JSON structure for per-MPN specs. Versioned via in . - PDF page selection — heuristics to pick pages most likely to contain pinouts, e-chars, applications, SPICE models. - Quality scoring — weighted rubric (pin coverage, voltage ratings, application info, electrical chars, SPICE specs).…

, nu)\n if m:\n return float(f\"{m.group(1)}.{m.group(2)}\")\n # Plain voltage: 5V → 5.0, 12V → 12.0\n m = re.match(r'^(\\d+\\.?\\d*)V?

Datasheets Skill Purpose Extract structured, machine-readable specifications from component datasheet PDFs and make them available to analyzer skills. Works on whatever PDFs are downloaded under (downloads are owned by distributor skills like , , , ). Scope This skill owns: - Extraction schema — the canonical JSON structure for per-MPN specs. Versioned via in . - PDF page selection — heuristics to pick pages most likely to contain pinouts, e-chars, applications, SPICE models. - Quality scoring — weighted rubric (pin coverage, voltage ratings, application info, electrical chars, SPICE specs).…

, nu)\n if m:\n return float(m.group(1))\n\n return None\n\n\ndef verify_pin_voltages(components: list, nets: dict, extraction_dir: str,\n rail_voltages: dict) -> list:\n \"\"\"P1: Verify pin voltage boundaries against datasheet abs max / operating ranges.\n\n For each IC with an extraction, checks every pin's connected net voltage\n against the pin's voltage_abs_max and voltage_operating_max from the\n extraction.\n\n Returns list of finding dicts.\n \"\"\"\n findings = []\n\n for comp in components:\n if comp.get(\"type\") != \"ic\":\n continue\n ref = comp[\"reference\"]\n mpn = comp.get(\"mpn\") or comp.get(\"value\", \"\")\n if not mpn or mpn == ref:\n continue\n\n extraction = _load_extraction(extraction_dir, mpn)\n if not extraction or not extraction.get(\"pins\"):\n continue\n\n pin_nets = comp.get(\"pin_nets\", {})\n if not pin_nets:\n continue\n\n # Build pin lookup from extraction: pin_number → pin_data\n ext_pins = {}\n for p in extraction[\"pins\"]:\n pnum = str(p.get(\"number\", \"\"))\n if pnum:\n ext_pins[pnum] = p\n\n for pin_num, net_name in pin_nets.items():\n ext_pin = ext_pins.get(pin_num)\n if not ext_pin:\n continue\n\n # Skip GND pins\n pin_type = (ext_pin.get(\"type\") or \"\").lower()\n if pin_type in (\"ground\", \"gnd\"):\n continue\n\n v_abs_max = ext_pin.get(\"voltage_abs_max\")\n v_op_max = ext_pin.get(\"voltage_operating_max\")\n net_voltage = _estimate_net_voltage(net_name, rail_voltages)\n\n if net_voltage is None:\n continue\n\n pin_name = ext_pin.get(\"name\", f\"pin {pin_num}\")\n\n # Check abs max violation\n if v_abs_max is not None and net_voltage > v_abs_max:\n findings.append({\n \"type\": \"pin_voltage_abs_max_exceeded\",\n \"severity\": \"CRITICAL\",\n \"ref\": ref,\n \"mpn\": mpn,\n \"pin_number\": pin_num,\n \"pin_name\": pin_name,\n \"net\": net_name,\n \"net_voltage_V\": net_voltage,\n \"abs_max_V\": v_abs_max,\n \"margin_V\": round(v_abs_max - net_voltage, 3),\n \"detail\": (f\"{ref} pin {pin_num} ({pin_name}) on {net_name} \"\n f\"({net_voltage}V) exceeds absolute maximum \"\n f\"({v_abs_max}V) by {net_voltage - v_abs_max:.2f}V\"),\n })\n # Check operating range exceeded (warning, not critical)\n elif v_op_max is not None and net_voltage > v_op_max:\n margin_pct = (v_abs_max - net_voltage) / v_abs_max * 100 if v_abs_max else 0\n findings.append({\n \"type\": \"pin_voltage_operating_exceeded\",\n \"severity\": \"HIGH\" if margin_pct \u003c 10 else \"MEDIUM\",\n \"ref\": ref,\n \"mpn\": mpn,\n \"pin_number\": pin_num,\n \"pin_name\": pin_name,\n \"net\": net_name,\n \"net_voltage_V\": net_voltage,\n \"operating_max_V\": v_op_max,\n \"abs_max_V\": v_abs_max,\n \"detail\": (f\"{ref} pin {pin_num} ({pin_name}) on {net_name} \"\n f\"({net_voltage}V) exceeds recommended operating \"\n f\"maximum ({v_op_max}V)\"),\n })\n\n return findings\n\n\ndef verify_required_externals(components: list, nets: dict, extraction_dir: str,\n comp_lookup: dict) -> list:\n \"\"\"P1: Verify required external components per datasheet pin specs.\n\n Checks pins with 'required_external' field in extraction — these are\n pins where the datasheet says \"connect X here\" (bypass cap, pull-up,\n inductor, etc.). Verifies something appropriate is actually connected.\n\n Returns list of finding dicts.\n \"\"\"\n findings = []\n\n for comp in components:\n if comp.get(\"type\") != \"ic\":\n continue\n ref = comp[\"reference\"]\n mpn = comp.get(\"mpn\") or comp.get(\"value\", \"\")\n if not mpn or mpn == ref:\n continue\n\n extraction = _load_extraction(extraction_dir, mpn)\n if not extraction or not extraction.get(\"pins\"):\n continue\n\n pin_nets = comp.get(\"pin_nets\", {})\n\n ext_pins = {}\n for p in extraction[\"pins\"]:\n pnum = str(p.get(\"number\", \"\"))\n if pnum:\n ext_pins[pnum] = p\n\n for pin_num, net_name in pin_nets.items():\n ext_pin = ext_pins.get(pin_num)\n if not ext_pin:\n continue\n\n required = ext_pin.get(\"required_external\")\n if not required:\n continue\n\n pin_name = ext_pin.get(\"name\", f\"pin {pin_num}\")\n pin_type = (ext_pin.get(\"type\") or \"\").lower()\n\n # Skip ground pins (always connected)\n if pin_type in (\"ground\", \"gnd\"):\n continue\n\n # Check what's connected to this pin's net\n net_info = nets.get(net_name, {})\n net_pins = net_info.get(\"pins\", []) if isinstance(net_info, dict) else []\n\n # Find other components on this net (excluding the IC itself)\n connected_refs = set()\n connected_types = set()\n for p in net_pins:\n c_ref = p.get(\"component\", \"\")\n if c_ref and c_ref != ref:\n connected_refs.add(c_ref)\n c = comp_lookup.get(c_ref, {})\n connected_types.add(c.get(\"type\", \"\"))\n\n # Parse required_external for expected component types\n req_lower = required.lower()\n expected_types = set()\n if any(k in req_lower for k in (\"cap\", \"capacitor\", \"decoupling\", \"bypass\")):\n expected_types.add(\"capacitor\")\n if any(k in req_lower for k in (\"resistor\", \"pull-up\", \"pullup\", \"pull-down\", \"divider\")):\n expected_types.add(\"resistor\")\n if any(k in req_lower for k in (\"inductor\", \"ferrite\", \"bead\")):\n expected_types.update((\"inductor\", \"ferrite_bead\"))\n if any(k in req_lower for k in (\"diode\", \"schottky\")):\n expected_types.add(\"diode\")\n\n if not expected_types:\n continue # Can't parse requirement — skip\n\n # Check if any expected type is connected\n if not expected_types & connected_types:\n # Nothing matching the requirement is connected\n findings.append({\n \"type\": \"missing_required_external\",\n \"severity\": \"HIGH\",\n \"ref\": ref,\n \"mpn\": mpn,\n \"pin_number\": pin_num,\n \"pin_name\": pin_name,\n \"net\": net_name,\n \"required\": required,\n \"expected_types\": sorted(expected_types),\n \"connected_types\": sorted(connected_types),\n \"detail\": (f\"{ref} pin {pin_num} ({pin_name}): datasheet requires \"\n f\"\\\"{required}\\\" but none found on net {net_name}\"),\n })\n\n return findings\n\n\ndef _parse_cap_recommendation(text: str) -> dict:\n \"\"\"Parse a capacitor recommendation string into structured requirements.\n\n Examples:\n \"10uF ceramic, X5R or X7R\" -> {min_farads: 10e-6, count: 1, dielectric: [\"X5R\",\"X7R\"]}\n \"22uF ceramic x2\" -> {min_farads: 22e-6, count: 2}\n \"100nF\" -> {min_farads: 100e-9, count: 1}\n \"\"\"\n from kicad_utils import parse_value\n\n result = {\"min_farads\": None, \"count\": 1, \"dielectric\": [], \"max_distance_mm\": None}\n\n if not text:\n return result\n\n text_lower = text.lower()\n\n # Extract count: \"x2\", \"x3\", \"x 2\"\n count_match = re.search(r'[x\\u00d7]\\s*(\\d+)', text_lower)\n if count_match:\n result[\"count\"] = int(count_match.group(1))\n\n # Extract distance: \"within 10mm\", \"\u003c 5mm\"\n dist_match = re.search(r'within\\s+(\\d+\\.?\\d*)\\s*mm', text_lower)\n if not dist_match:\n dist_match = re.search(r'\u003c\\s*(\\d+\\.?\\d*)\\s*mm', text_lower)\n if dist_match:\n result[\"max_distance_mm\"] = float(dist_match.group(1))\n\n # Extract dielectric: X5R, X7R, C0G, NP0\n for d in (\"X5R\", \"X7R\", \"X7S\", \"C0G\", \"NP0\", \"X6S\"):\n if d.lower() in text_lower:\n result[\"dielectric\"].append(d)\n\n # Extract capacitance value\n cap_match = re.search(r'(\\d+\\.?\\d*)\\s*(uF|\\u00b5F|nF|pF|u|n|p)', text, re.IGNORECASE)\n if cap_match:\n val_str = cap_match.group(1) + cap_match.group(2)\n parsed = parse_value(val_str, component_type=\"capacitor\")\n if parsed:\n result[\"min_farads\"] = parsed\n\n return result\n\n\ndef verify_decoupling(components: list, nets: dict, extraction_dir: str,\n comp_lookup: dict, parsed_values: dict) -> list:\n \"\"\"P2: Verify per-IC decoupling against datasheet application circuit.\n\n For each IC with an extraction containing application_circuit.decoupling_cap\n or input_cap_recommended / output_cap_recommended, checks that the actual\n caps on power pins meet the requirements (count, value, type).\n\n Returns list of finding dicts.\n \"\"\"\n findings = []\n\n for comp in components:\n if comp.get(\"type\") != \"ic\":\n continue\n ref = comp[\"reference\"]\n mpn = comp.get(\"mpn\") or comp.get(\"value\", \"\")\n if not mpn or mpn == ref:\n continue\n\n extraction = _load_extraction(extraction_dir, mpn)\n app_circuit = extraction.get(\"application_circuit\", {})\n if not app_circuit:\n continue\n\n pin_nets = comp.get(\"pin_nets\", {})\n ext_pins = {str(p.get(\"number\", \"\")): p for p in extraction.get(\"pins\", [])}\n\n # Collect recommendations\n recommendations = []\n for key in (\"input_cap_recommended\", \"output_cap_recommended\", \"decoupling_cap\"):\n text = app_circuit.get(key)\n if text:\n recommendations.append((key, text, _parse_cap_recommendation(text)))\n\n if not recommendations:\n continue\n\n # Find power pins and their connected caps\n power_pin_nets = set()\n for pin_num, net_name in pin_nets.items():\n ep = ext_pins.get(pin_num)\n if ep:\n pt = (ep.get(\"type\") or \"\").lower()\n direction = (ep.get(\"direction\") or \"\").lower()\n if pt in (\"power\",) and direction in (\"input\", \"output\", \"bidirectional\"):\n power_pin_nets.add(net_name)\n\n # Count caps on power nets\n caps_on_power = []\n for net_name in power_pin_nets:\n net_info = nets.get(net_name, {})\n for p in net_info.get(\"pins\", []) if isinstance(net_info, dict) else []:\n c_ref = p.get(\"component\", \"\")\n c = comp_lookup.get(c_ref, {})\n if c.get(\"type\") == \"capacitor\" and c_ref != ref:\n cap_val = parsed_values.get(c_ref, 0)\n caps_on_power.append({\n \"ref\": c_ref,\n \"value\": c.get(\"value\", \"\"),\n \"farads\": cap_val,\n \"net\": net_name,\n })\n\n # Check each recommendation\n for key, text, req in recommendations:\n if req[\"min_farads\"] is None:\n continue\n\n # Find matching caps (value >= recommended)\n matching = [c for c in caps_on_power if c[\"farads\"] >= req[\"min_farads\"] * 0.8]\n total_matching = len(matching)\n\n if total_matching \u003c req[\"count\"]:\n severity = \"HIGH\" if total_matching == 0 else \"MEDIUM\"\n findings.append({\n \"type\": \"decoupling_insufficient\",\n \"severity\": severity,\n \"ref\": ref,\n \"mpn\": mpn,\n \"requirement_key\": key,\n \"requirement_text\": text,\n \"required_count\": req[\"count\"],\n \"required_min_farads\": req[\"min_farads\"],\n \"actual_count\": total_matching,\n \"actual_caps\": [{\"ref\": c[\"ref\"], \"value\": c[\"value\"]} for c in caps_on_power],\n \"detail\": (f\"{ref} ({mpn}): datasheet recommends \\\"{text}\\\" \"\n f\"but found {total_matching}/{req['count']} matching caps \"\n f\"on power pins\"),\n })\n\n return findings\n\n\ndef run_datasheet_verification(analysis: dict, project_dir: str = \"\") -> dict:\n \"\"\"Run all datasheet verification checks.\n\n Args:\n analysis: Full schematic analysis JSON (from analyze_schematic.py)\n project_dir: Project directory for finding datasheets/extracted/\n\n Returns dict with:\n findings: list of verification findings\n summary: {ics_checked, ics_with_extractions, total_findings, by_severity}\n \"\"\"\n components = analysis.get(\"components\", [])\n nets = analysis.get(\"nets\", {})\n rail_voltages = analysis.get(\"rail_voltages\", {})\n parsed_values = {}\n comp_lookup = {}\n for c in components:\n ref = c.get(\"reference\", \"\")\n comp_lookup[ref] = c\n pv = c.get(\"parsed_value\")\n if isinstance(pv, (int, float)):\n parsed_values[ref] = pv\n elif isinstance(pv, dict):\n parsed_values[ref] = pv.get(\"value\", 0)\n\n # Resolve extraction directory\n if not project_dir:\n src_file = analysis.get(\"file\", \"\")\n if src_file:\n project_dir = os.path.dirname(os.path.abspath(src_file))\n extract_dir = _resolve_extract_dir(project_dir) if project_dir else \"\"\n\n if not extract_dir:\n return {\"findings\": [], \"summary\": {\n \"ics_checked\": 0, \"ics_with_extractions\": 0,\n \"total_findings\": 0, \"by_severity\": {},\n \"note\": \"No datasheets/extracted/ directory found\",\n }}\n\n # Count ICs with extractions\n ic_count = 0\n ic_with_ext = 0\n for c in components:\n if c.get(\"type\") == \"ic\":\n ic_count += 1\n mpn = c.get(\"mpn\") or c.get(\"value\", \"\")\n if mpn and _load_extraction(extract_dir, mpn):\n ic_with_ext += 1\n\n # Run checks\n all_findings = []\n all_findings.extend(verify_pin_voltages(components, nets, extract_dir, rail_voltages))\n all_findings.extend(verify_required_externals(components, nets, extract_dir, comp_lookup))\n all_findings.extend(verify_decoupling(components, nets, extract_dir, comp_lookup, parsed_values))\n\n # Build severity summary\n by_severity = {}\n for f in all_findings:\n sev = f.get(\"severity\", \"INFO\")\n by_severity[sev] = by_severity.get(sev, 0) + 1\n\n return {\n \"findings\": all_findings,\n \"summary\": {\n \"ics_checked\": ic_count,\n \"ics_with_extractions\": ic_with_ext,\n \"total_findings\": len(all_findings),\n \"by_severity\": by_severity,\n },\n }\n","content_type":"text/x-python; charset=utf-8","language":"python","size":18738,"content_sha256":"279d8597727b5e7095e2e928e09093108c9f3b0ef4f7fed5ac33bea048b3cbe0"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Datasheets Skill","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Purpose","type":"text"}]},{"type":"paragraph","content":[{"text":"Extract structured, machine-readable specifications from component datasheet PDFs and make them available to analyzer skills. Works on whatever PDFs are downloaded under ","type":"text"},{"text":"\u003cproject>/datasheets/","type":"text","marks":[{"type":"code_inline"}]},{"text":" (downloads are owned by distributor skills like ","type":"text"},{"text":"digikey","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"mouser","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"lcsc","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"element14","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Scope","type":"text"}]},{"type":"paragraph","content":[{"text":"This skill owns:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Extraction schema","type":"text","marks":[{"type":"strong"}]},{"text":" — the canonical JSON structure for per-MPN specs. Versioned via ","type":"text"},{"text":"EXTRACTION_VERSION","type":"text","marks":[{"type":"code_inline"}]},{"text":" in ","type":"text"},{"text":"scripts/datasheet_extract_cache.py","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PDF page selection","type":"text","marks":[{"type":"strong"}]},{"text":" — heuristics to pick pages most likely to contain pinouts, e-chars, applications, SPICE models.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Quality scoring","type":"text","marks":[{"type":"strong"}]},{"text":" — weighted rubric (pin coverage, voltage ratings, application info, electrical chars, SPICE specs).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Consumer API","type":"text","marks":[{"type":"strong"}]},{"text":" — helpers in ","type":"text"},{"text":"scripts/datasheet_features.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" for other skills to query specific fields (e.g., ","type":"text"},{"text":"get_regulator_features(mpn)","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"get_mcu_features(mpn)","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Verification","type":"text","marks":[{"type":"strong"}]},{"text":" — consistency checks between extracted data and schematic/PCB usage.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Non-goals","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"No PDF downloading.","type":"text","marks":[{"type":"strong"}]},{"text":" That is owned by distributor skills (","type":"text"},{"text":"digikey","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"mouser","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"lcsc","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"element14","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"No global library.","type":"text","marks":[{"type":"strong"}]},{"text":" Each project's extractions live in ","type":"text"},{"text":"\u003cproject>/datasheets/extracted/","type":"text","marks":[{"type":"code_inline"}]},{"text":". There is no shared cross-project cache.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Cache location","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"\u003cproject>/\n design.kicad_sch\n datasheets/\n TPS61023DRLR.pdf # downloaded by distributor skills\n extracted/\n manifest.json # extraction manifest (legacy name: index.json)\n TPS61023DRLR.json # structured extraction (this skill's output)","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reference guides","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/extraction-schema.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — canonical schema, every field defined","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/field-extraction-guide.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — how to find each field in datasheets from common vendors (TI, ST, NXP, Espressif, Microchip)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/quality-scoring.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — rubric details, score thresholds","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/consumer-api.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — how kicad/emc/spice/thermal consume extractions","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Entry-point scripts","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"scripts/datasheet_extract_cache.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" — cache manager, resolver, indexer","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"scripts/datasheet_page_selector.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" — page selection heuristics","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"scripts/datasheet_score.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" — extraction quality scoring","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"scripts/datasheet_verify.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" — cross-check extraction vs schematic usage","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"scripts/datasheet_features.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" — consumer helper API (new in v1.3)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Extraction workflow","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User runs an analyzer or requests extraction.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"This skill checks the cache (","type":"text"},{"text":"\u003cproject>/datasheets/extracted/\u003cMPN>.json","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"On cache miss / stale / low score: Claude reads selected PDF pages and extracts structured data.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Extraction is scored; if score ≥ 6.0, cached.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Consumers query via ","type":"text"},{"text":"datasheet_features.py","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to trigger this skill","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Immediately after downloading datasheets","type":"text","marks":[{"type":"strong"}]},{"text":" via ","type":"text"},{"text":"sync_datasheets_digikey.py","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"sync_datasheets_lcsc.py","type":"text","marks":[{"type":"code_inline"}]},{"text":", or equivalent. Without extraction, IC-aware checks (VM-001 rail voltage, PS-001 power-good, PR-004 USB, DP-002 USB speed classification) fall back to heuristics on unknown ICs.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Before running analyzers on a new project","type":"text","marks":[{"type":"strong"}]},{"text":" where datasheets are present but ","type":"text"},{"text":"datasheets/extracted/","type":"text","marks":[{"type":"code_inline"}]},{"text":" is empty — the analyzers won't produce the extractions themselves.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When a review flags low trust level","type":"text","marks":[{"type":"strong"}]},{"text":" due to missing manufacturer evidence: extracting the ICs referenced by power regulators, MCUs, and high-speed peripherals typically flips ","type":"text"},{"text":"trust_level: low","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"mixed","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"high","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When a user asks for pin verification","type":"text","marks":[{"type":"strong"}]},{"text":" (\"verify U1 pin names match datasheet\") — this skill's cached extraction is the authoritative source.","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"datasheets","author":"@skillopedia","source":{"stars":464,"repo_name":"kicad-happy","origin_url":"https://github.com/aklofas/kicad-happy/blob/HEAD/skills/datasheets/SKILL.md","repo_owner":"aklofas","body_sha256":"225e11e5507a2082452a5f11fa8cbd578b31f45af795d2d82f4bcfd30537484a","cluster_key":"5d78f71dd3dad44b0b9a4cdd2b0f9f6b32c4ddca576d6679d20d8feacf0c5a7b","clean_bundle":{"format":"clean-skill-bundle-v1","source":"aklofas/kicad-happy/skills/datasheets/SKILL.md","attachments":[{"id":"d677f2c4-1f25-5d55-a4ad-1922bfb1f607","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/d677f2c4-1f25-5d55-a4ad-1922bfb1f607/attachment.md","path":"references/consumer-api.md","size":8834,"sha256":"3e0392751aa3b264418a405b5abc5ae7ad54e2759a8922f370c661043003194a","contentType":"text/markdown; charset=utf-8"},{"id":"dfdafc7f-e7b0-574d-9517-ee0f541df914","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/dfdafc7f-e7b0-574d-9517-ee0f541df914/attachment.md","path":"references/extraction-schema.md","size":17893,"sha256":"2cb553dd8d5fd4e4e2533a957958e98bbb6ada7ce29bbd0db43761f66f07d469","contentType":"text/markdown; charset=utf-8"},{"id":"1073777c-7f5c-59cf-8f23-b4b80a52add8","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/1073777c-7f5c-59cf-8f23-b4b80a52add8/attachment.md","path":"references/field-extraction-guide.md","size":14420,"sha256":"d0d4aa4d10bbb9ef30ac609c4edc66cdc63b9581e97560cdc21cc0ba972c20a9","contentType":"text/markdown; charset=utf-8"},{"id":"ffa32332-f226-5678-92d9-45a8f50a831f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ffa32332-f226-5678-92d9-45a8f50a831f/attachment.md","path":"references/quality-scoring.md","size":7937,"sha256":"8a981a69735dbecac2d97482a06f66aa18ae4f9e2751d48e10111388c56517ed","contentType":"text/markdown; charset=utf-8"},{"id":"6f466270-b0a2-5207-83d3-bec55d5b63ce","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6f466270-b0a2-5207-83d3-bec55d5b63ce/attachment.py","path":"scripts/datasheet_extract_cache.py","size":18478,"sha256":"391a141a9360ca2226eb6263f5f0f465dbdae4fc70a42c92cc54eb85a44db16d","contentType":"text/x-python; charset=utf-8"},{"id":"4455eb37-49b8-5158-803e-697039a19ce8","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4455eb37-49b8-5158-803e-697039a19ce8/attachment.py","path":"scripts/datasheet_features.py","size":6237,"sha256":"2a4df6d0aac516a770d4942bb37066a963a7338952d237fa0acb16a7ad860c77","contentType":"text/x-python; charset=utf-8"},{"id":"4601d563-9f0c-5385-ae59-8cd1fde013b9","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4601d563-9f0c-5385-ae59-8cd1fde013b9/attachment.py","path":"scripts/datasheet_page_selector.py","size":17048,"sha256":"15201b5acdcdbc63708bd6e2162cc3bcbbdcdeb6b4923da7fc11625bd6ede5d9","contentType":"text/x-python; charset=utf-8"},{"id":"e021876a-0b65-50f0-b34c-5147c1b66b17","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e021876a-0b65-50f0-b34c-5147c1b66b17/attachment.py","path":"scripts/datasheet_score.py","size":11792,"sha256":"8ed695711d4d87832edd102ce314f80a5e25e0e46543fd781b70e3710d9a574b","contentType":"text/x-python; charset=utf-8"},{"id":"816c1240-3931-56e2-bbaf-abf67b419dad","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/816c1240-3931-56e2-bbaf-abf67b419dad/attachment.py","path":"scripts/datasheet_verify.py","size":18738,"sha256":"279d8597727b5e7095e2e928e09093108c9f3b0ef4f7fed5ac33bea048b3cbe0","contentType":"text/x-python; charset=utf-8"}],"bundle_sha256":"c9ebef303ad0a60e7ced06c1ac48d2ba04ca190abdecc20d684ee73fb779a9e4","attachment_count":9,"text_attachments":9,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/datasheets/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"devops-infrastructure","category_label":"DevOps"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"devops-infrastructure","import_tag":"clean-skills-v1","description":"Extract structured specifications from electronic component datasheet PDFs — pinouts, electrical characteristics, peripherals, topology, and features. Cache extractions per project for consumption by schematic and PCB analyzers. Primary consumer infrastructure for `kicad`, `emc`, `spice`, and `thermal` analyzers. Use this skill whenever the user asks to extract, verify, or read specs from a component datasheet; when analyzers need verified IC knowledge (EN pin thresholds, PG presence, USB peripheral speed); or when a review mentions datasheet coverage, extraction quality, or per-MPN specifications. Also triggers on \"extract this datasheet\", \"what are the specs for MPN X\", \"verify datasheet extraction\", or \"check pin functions for part Y\"."}},"renderedAt":1782986983472}

Datasheets Skill Purpose Extract structured, machine-readable specifications from component datasheet PDFs and make them available to analyzer skills. Works on whatever PDFs are downloaded under (downloads are owned by distributor skills like , , , ). Scope This skill owns: - Extraction schema — the canonical JSON structure for per-MPN specs. Versioned via in . - PDF page selection — heuristics to pick pages most likely to contain pinouts, e-chars, applications, SPICE models. - Quality scoring — weighted rubric (pin coverage, voltage ratings, application info, electrical chars, SPICE specs).…