Adom DS2SF - Datasheet to Symbol and Footprint
Public Made by Adomby adom
Datasheet to symbol + footprint + provenance JSON — pins and pads, extracted from the PDF.
name: adom-ds2sf description: Datasheet â symbol + footprint + provenance JSON. Reads a chip's datasheet PDF and emits sym_create-shaped symbol JSON, footprint metadata, a field-level provenance audit trail, and an agent-to-agent result.json with stable exit codes for programmatic re-search-and-retry. Trigger words â adom-ds2sf, datasheet to symbol, datasheet to footprint, extract symbol from datasheet, extract footprint from datasheet, datasheet pinout extract, sym extracted json, fp extracted json, datasheet sym fp, chip pin grouping, pin provenance, footprint provenance, sym_create input from datasheet, adom-ds2sf result.json, datasheet extractor agent contract.
adom-ds2sf â datasheet â symbol + footprint + provenance
Pipeline: read a adom-chip-fetcher chip directory, send the datasheet PDF to Claude in two focused passes (symbol â footprint), normalize the package against the service-kicad standard library, and emit four JSON files alongside the existing adom-chip-fetcher artifacts.
â Always Opus, never Haiku
Production runs MUST use the default --model claude-opus-4-7. EEs rely on this output to wire schematics; Haiku's chip-data misreads are not acceptable in that pipeline. Concur (the cross-source consensus check) does catch most Haiku errors via 4-source consensus, but the right answer is to not produce them in the first place. Override the model only for development experiments where a follow-up Opus pass is acceptable.
When to use
- After
adom-chip-fetcherlands a chip into~/project/adom-chip-fetcher/library/<MPN>/. - When you want an Adom-grouped symbol (POWER / I2C / GPIO / etc.) â the UL bundle's
.kicad_symis flat and ungrouped. - When you need a downstream-ready
sym_createinput JSON. - When you need page-level provenance to deeplink the Adom user back to the datasheet PDF page each fact came from.
Module products: pass --pdf explicitly
For module products (ESP32-WROOM, NORA, ATWINC, SARA-R5, etc.), adom-chip-fetcher's auto-named <MPN>.pdf may be the internal SoC datasheet â which has the SoC's pinout, not the module's external castellated-pad pinout. The extractor will refuse to hallucinate (writes a result.json with status: "needs_better_pdf" and a list of candidate PDFs already on disk).
Look for the module-specific PDF in the chip-dir (<MPN>-original.pdf, <MPN>-datasheethardware-guideline.pdf, etc.) and pass it via --pdf:
adom-ds2sf extract /home/adom/project/adom-chip-fetcher/library/ESP32-S3-WROOM-1-N4 \
--pdf /home/adom/project/adom-chip-fetcher/library/ESP32-S3-WROOM-1-N4/ESP32-S3-WROOM-1-N4-original.pdf
Commands
adom-ds2sf extract <CHIP-DIR>
Run the full pipeline against a chip directory.
| Flag | Description |
|---|---|
--pdf <path> |
Override auto-detected datasheet (default <dir>/<basename>.pdf). |
--mpn <id> |
Override the MPN. |
--manufacturer <name> |
Override the manufacturer. |
--datasheet-url <url> |
Override the datasheet URL. |
--source-tier <mfr|snapmagic|mouser|digikey|arrow|cse|lcsc|unknown> |
Override the upstream provenance tier. |
--out-dir <path> |
Output directory (default: chip-dir). |
--model <id> |
Claude model (default claude-opus-4-7). Always use Opus for production EE work. Haiku produces frequent misreads on chip data â pin-order swaps (DMG2305 GDSâGSD), pad undercounts (ICE40UP5K saw 24 of 48), package-variant confusion (WSL2010 â WSL2512), and JTAG-letter typos (MTDO â MTD0). Concur catches these via cross-source consensus, but the right answer is to never let them happen: use Opus. Only override to a cheaper model for development testing where a follow-up Opus run is acceptable. |
--force |
Bypass cache, re-run Claude. |
--symbol-only |
Skip footprint pass. |
--footprint-only |
Re-run only footprint pass against cached symbol. |
--json-only |
Suppress progress; only OK: / ERROR: lines. |
Example:
adom-ds2sf extract /home/adom/project/adom-chip-fetcher/library/ADS1115IDGSR
adom-ds2sf normalize <PACKAGE>
Resolve a package string against service-kicad's standard library (debug aid).
adom-ds2sf normalize "VSSOP-10"
# OK: VSSOP-10 â Package_SO:MSOP-10_3x3mm_P0.5mm (service-kicad stdlib)
adom-ds2sf inspect <CHIP-DIR>
Print a summary of an existing extraction without re-running anything.
adom-ds2sf health
Probe claude CLI + service-kicad reachability.
adom-ds2sf install
Drop this SKILL.md into ~/.claude/skills/adom-ds2sf/.
Outputs
<chip-dir>/
<MPN>-symbol.extracted.json # sym_create-shaped (only on status=ok)
<MPN>-footprint.extracted.json # fp-metadata-shaped (only on status=ok)
<MPN>-extraction.provenance.json # audit trail (only on status=ok)
<MPN>-extraction.result.json # agent-to-agent contract (always written)
.ds2sf-cache/ # raw Claude responses for re-emit / debug
The provenance JSON is the audit trail. Open the file, pick a pin, follow pin_provenance[i].page â open that page in the datasheet PDF â confirm the pin name + description are visibly there. Same for footprint dimensions via dimension_provenance[i].page + figure_label.
Agent-to-agent contract
adom-ds2sf is built so an upstream agent (adom-chip-fetcher, automation) can call it programmatically, read the result, and decide what to do next without human input.
Exit codes
| Exit | status |
Meaning | Caller action |
|---|---|---|---|
| 0 | ok |
Extraction completed. review_required[] may still have entries â they're informational, not blocking. |
Accept the outputs. |
| 2 | needs_better_pdf |
Extractor refused because the supplied PDF doesn't have the right data (typically: SoC datasheet was passed for a module, or wrong package variant). | Try one of hints[].candidates and re-call with --pdf <new>. |
| 3 | unrecoverable |
Hard failure (Claude returned malformed output twice; pre-flight failure; emit error). | Surface to a human; inspect .ds2sf-cache/. |
<MPN>-extraction.result.json shape
Always written. Stable schema (schema_version: "1"):
{
"schema_version": "1",
"status": "ok | needs_better_pdf | unrecoverable",
"exit_code": 0 | 2 | 3,
"mpn": "ADS1115IDGSR",
"manufacturer": "TI",
"datasheet_used": "/home/.../ADS1115IDGSR.pdf",
"datasheet_sha256": "65231e81â¦",
"summary": "ADS1115IDGSR â 10 pins, package VSSOP-10 â¦",
"review_required": [ ⦠merged from symbol + footprint passes ⦠],
"hints": [
{ "action": "try_alternate_pdf",
"reason": "module_external_pinout_missing",
"candidates": ["/path/to/X-original.pdf", "/path/to/X-hardware-guidelines.pdf"] },
{ "action": "update_upstream_metadata",
"file": "/path/to/info.json",
"key": "package",
"current": "VQFN-32 (5Ã5Ã0.9 mm)",
"extracted": "VQFN-40 (7Ã5Ã0.9 mm)" },
{ "action": "use_datasheet_extracted_footprint",
"package": "Optical LGA-16" },
{ "action": "human_review",
"reason": "muxed_pin_protocol_select",
"notes": "â¦" }
],
"outputs": {
"symbol_json": "/path/to/X-symbol.extracted.json | null",
"footprint_json": "/path/to/X-footprint.extracted.json | null",
"provenance_json": "/path/to/X-extraction.provenance.json | null"
},
"extractor_version": "0.1.0",
"claude_model": "claude-opus-4-7"
}
Canonical review_required.reason values
| Reason | When | Caller action |
|---|---|---|
module_external_pinout_missing |
Empty pins[] returned because the supplied PDF was a SoC datasheet for a module product. | hints[].try_alternate_pdf â re-call with one of the candidate PDFs. |
package_mismatch_in_hint |
info.json's package disagrees with the datasheet's actual package. |
hints[].update_upstream_metadata â patch info.json's package to match extracted, then accept. |
non_standard_package_no_kicad_baseline |
The package isn't in service-kicad's stdlib (custom OLGA, modules, optical). | hints[].use_datasheet_extracted_footprint â use <MPN>-footprint.extracted.json's bodyDimensions + leadDimensions directly. |
muxed_pin_protocol_select |
Some pins (e.g. SDA/MOSI) are protocol-multiplexed. | Informational. Pin descriptions in provenance explain how. |
pad_dimensions_from_example_layout |
Footprint dims came from an "Example Board Layout" rather than a formal recommended land pattern. | Informational; recommend cross-check vs IPC-7351. |
boot_strapping_pins, vdd_spi_voltage_dependency, psram_variant_conflict, non_uniform_pad_pitch, power_supply_configuration, thermal_management, i2c_address_multidevice |
Engineering nuances Claude flagged for human review. | Surface to schematic designer. |
unrecoverable_extraction_error |
Claude returned malformed JSON twice in a row. | Surface to a human; inspect raw responses in .ds2sf-cache/. |
Agent calling recipe
// (Pseudo-Rust for adom-chip-fetcher's caller side.)
fn run_ds2sf(chip_dir: &Path, pdf_override: Option<&Path>) -> ResultDoc {
let mut cmd = Command::new("adom-ds2sf");
cmd.arg("extract").arg(chip_dir).arg("--force").arg("--json-only");
if let Some(p) = pdf_override { cmd.arg("--pdf").arg(p); }
let _ = cmd.status(); // exit code mirrored in result.json
let path = chip_dir.join(format!("{}-extraction.result.json", basename(chip_dir)));
serde_json::from_str(&fs::read_to_string(path).unwrap()).unwrap()
}
let mut tried: HashSet<PathBuf> = HashSet::new();
let mut r = run_ds2sf(chip_dir, None);
tried.insert(r.datasheet_used.clone());
while r.status == "needs_better_pdf" {
// Pull the first try_alternate_pdf hint we haven't already tried.
let next = r.hints.iter()
.filter_map(|h| if let Hint::TryAlternatePdf { candidates, .. } = h { Some(candidates) } else { None })
.flatten()
.find(|c| !tried.contains(*c));
let Some(next) = next else {
// Out of candidates â escalate to human.
log_for_review(&r); break;
};
tried.insert(next.clone());
r = run_ds2sf(chip_dir, Some(next));
}
match r.status.as_str() {
"ok" => {
accept(r.outputs);
// Apply update_upstream_metadata hints (e.g. fix info.json's package).
for h in &r.hints {
if let Hint::UpdateUpstreamMetadata { file, key, extracted, .. } = h {
patch_json(file, key, extracted);
}
}
}
"unrecoverable" => log_for_review(&r),
_ => unreachable!(),
}
Caching behavior under cache-hit
If <MPN>-extraction.provenance.json already exists and --force is not passed, adom-ds2sf skips the Claude calls entirely and exits with the cached result.json's exit code. Re-running is idempotent.
---
name: adom-ds2sf
description: Datasheet â symbol + footprint + provenance JSON. Reads a chip's datasheet PDF and emits sym_create-shaped symbol JSON, footprint metadata, a field-level provenance audit trail, and an agent-to-agent result.json with stable exit codes for programmatic re-search-and-retry. Trigger words â adom-ds2sf, datasheet to symbol, datasheet to footprint, extract symbol from datasheet, extract footprint from datasheet, datasheet pinout extract, sym extracted json, fp extracted json, datasheet sym fp, chip pin grouping, pin provenance, footprint provenance, sym_create input from datasheet, adom-ds2sf result.json, datasheet extractor agent contract.
---
# adom-ds2sf â datasheet â symbol + footprint + provenance
Pipeline: read a adom-chip-fetcher chip directory, send the datasheet PDF to Claude in two focused passes (symbol â footprint), normalize the package against the service-kicad standard library, and emit four JSON files alongside the existing adom-chip-fetcher artifacts.
## â Always Opus, never Haiku
Production runs MUST use the default `--model claude-opus-4-7`. EEs rely on this output to wire schematics; Haiku's chip-data misreads are not acceptable in that pipeline. Concur (the cross-source consensus check) does catch most Haiku errors via 4-source consensus, but the right answer is to not produce them in the first place. Override the model only for development experiments where a follow-up Opus pass is acceptable.
## When to use
- After `adom-chip-fetcher` lands a chip into `~/project/adom-chip-fetcher/library/<MPN>/`.
- When you want an Adom-grouped symbol (POWER / I2C / GPIO / etc.) â the UL bundle's `.kicad_sym` is flat and ungrouped.
- When you need a downstream-ready `sym_create` input JSON.
- When you need page-level provenance to deeplink the Adom user back to the datasheet PDF page each fact came from.
## Module products: pass `--pdf` explicitly
For **module products** (ESP32-WROOM, NORA, ATWINC, SARA-R5, etc.), adom-chip-fetcher's auto-named `<MPN>.pdf` may be the internal SoC datasheet â which has the SoC's pinout, not the module's external castellated-pad pinout. The extractor will refuse to hallucinate (writes a result.json with `status: "needs_better_pdf"` and a list of candidate PDFs already on disk).
Look for the module-specific PDF in the chip-dir (`<MPN>-original.pdf`, `<MPN>-datasheethardware-guideline.pdf`, etc.) and pass it via `--pdf`:
```bash
adom-ds2sf extract /home/adom/project/adom-chip-fetcher/library/ESP32-S3-WROOM-1-N4 \
--pdf /home/adom/project/adom-chip-fetcher/library/ESP32-S3-WROOM-1-N4/ESP32-S3-WROOM-1-N4-original.pdf
```
## Commands
### `adom-ds2sf extract <CHIP-DIR>`
Run the full pipeline against a chip directory.
| Flag | Description |
|------|-------------|
| `--pdf <path>` | Override auto-detected datasheet (default `<dir>/<basename>.pdf`). |
| `--mpn <id>` | Override the MPN. |
| `--manufacturer <name>` | Override the manufacturer. |
| `--datasheet-url <url>` | Override the datasheet URL. |
| `--source-tier <mfr\|snapmagic\|mouser\|digikey\|arrow\|cse\|lcsc\|unknown>` | Override the upstream provenance tier. |
| `--out-dir <path>` | Output directory (default: chip-dir). |
| `--model <id>` | Claude model (default `claude-opus-4-7`). **Always use Opus for production EE work.** Haiku produces frequent misreads on chip data â pin-order swaps (DMG2305 GDSâGSD), pad undercounts (ICE40UP5K saw 24 of 48), package-variant confusion (WSL2010 â WSL2512), and JTAG-letter typos (MTDO â MTD0). Concur catches these via cross-source consensus, but the right answer is to never let them happen: use Opus. Only override to a cheaper model for development testing where a follow-up Opus run is acceptable. |
| `--force` | Bypass cache, re-run Claude. |
| `--symbol-only` | Skip footprint pass. |
| `--footprint-only` | Re-run only footprint pass against cached symbol. |
| `--json-only` | Suppress progress; only `OK:` / `ERROR:` lines. |
**Example:**
```bash
adom-ds2sf extract /home/adom/project/adom-chip-fetcher/library/ADS1115IDGSR
```
### `adom-ds2sf normalize <PACKAGE>`
Resolve a package string against service-kicad's standard library (debug aid).
```bash
adom-ds2sf normalize "VSSOP-10"
# OK: VSSOP-10 â Package_SO:MSOP-10_3x3mm_P0.5mm (service-kicad stdlib)
```
### `adom-ds2sf inspect <CHIP-DIR>`
Print a summary of an existing extraction without re-running anything.
### `adom-ds2sf health`
Probe `claude` CLI + service-kicad reachability.
### `adom-ds2sf install`
Drop this `SKILL.md` into `~/.claude/skills/adom-ds2sf/`.
## Outputs
```
<chip-dir>/
<MPN>-symbol.extracted.json # sym_create-shaped (only on status=ok)
<MPN>-footprint.extracted.json # fp-metadata-shaped (only on status=ok)
<MPN>-extraction.provenance.json # audit trail (only on status=ok)
<MPN>-extraction.result.json # agent-to-agent contract (always written)
.ds2sf-cache/ # raw Claude responses for re-emit / debug
```
The provenance JSON is the audit trail. Open the file, pick a pin, follow `pin_provenance[i].page` â open that page in the datasheet PDF â confirm the pin name + description are visibly there. Same for footprint dimensions via `dimension_provenance[i].page` + `figure_label`.
---
## Agent-to-agent contract
adom-ds2sf is built so an upstream agent (adom-chip-fetcher, automation) can call it programmatically, read the result, and decide what to do next without human input.
### Exit codes
| Exit | `status` | Meaning | Caller action |
|---|---|---|---|
| 0 | `ok` | Extraction completed. `review_required[]` may still have entries â they're informational, not blocking. | Accept the outputs. |
| 2 | `needs_better_pdf` | Extractor refused because the supplied PDF doesn't have the right data (typically: SoC datasheet was passed for a module, or wrong package variant). | Try one of `hints[].candidates` and re-call with `--pdf <new>`. |
| 3 | `unrecoverable` | Hard failure (Claude returned malformed output twice; pre-flight failure; emit error). | Surface to a human; inspect `.ds2sf-cache/`. |
### `<MPN>-extraction.result.json` shape
Always written. Stable schema (`schema_version: "1"`):
```json
{
"schema_version": "1",
"status": "ok | needs_better_pdf | unrecoverable",
"exit_code": 0 | 2 | 3,
"mpn": "ADS1115IDGSR",
"manufacturer": "TI",
"datasheet_used": "/home/.../ADS1115IDGSR.pdf",
"datasheet_sha256": "65231e81â¦",
"summary": "ADS1115IDGSR â 10 pins, package VSSOP-10 â¦",
"review_required": [ ⦠merged from symbol + footprint passes ⦠],
"hints": [
{ "action": "try_alternate_pdf",
"reason": "module_external_pinout_missing",
"candidates": ["/path/to/X-original.pdf", "/path/to/X-hardware-guidelines.pdf"] },
{ "action": "update_upstream_metadata",
"file": "/path/to/info.json",
"key": "package",
"current": "VQFN-32 (5Ã5Ã0.9 mm)",
"extracted": "VQFN-40 (7Ã5Ã0.9 mm)" },
{ "action": "use_datasheet_extracted_footprint",
"package": "Optical LGA-16" },
{ "action": "human_review",
"reason": "muxed_pin_protocol_select",
"notes": "â¦" }
],
"outputs": {
"symbol_json": "/path/to/X-symbol.extracted.json | null",
"footprint_json": "/path/to/X-footprint.extracted.json | null",
"provenance_json": "/path/to/X-extraction.provenance.json | null"
},
"extractor_version": "0.1.0",
"claude_model": "claude-opus-4-7"
}
```
### Canonical `review_required.reason` values
| Reason | When | Caller action |
|---|---|---|
| `module_external_pinout_missing` | Empty pins[] returned because the supplied PDF was a SoC datasheet for a module product. | `hints[].try_alternate_pdf` â re-call with one of the candidate PDFs. |
| `package_mismatch_in_hint` | info.json's `package` disagrees with the datasheet's actual package. | `hints[].update_upstream_metadata` â patch info.json's `package` to match `extracted`, then accept. |
| `non_standard_package_no_kicad_baseline` | The package isn't in service-kicad's stdlib (custom OLGA, modules, optical). | `hints[].use_datasheet_extracted_footprint` â use `<MPN>-footprint.extracted.json`'s `bodyDimensions` + `leadDimensions` directly. |
| `muxed_pin_protocol_select` | Some pins (e.g. SDA/MOSI) are protocol-multiplexed. | Informational. Pin descriptions in provenance explain how. |
| `pad_dimensions_from_example_layout` | Footprint dims came from an "Example Board Layout" rather than a formal recommended land pattern. | Informational; recommend cross-check vs IPC-7351. |
| `boot_strapping_pins`, `vdd_spi_voltage_dependency`, `psram_variant_conflict`, `non_uniform_pad_pitch`, `power_supply_configuration`, `thermal_management`, `i2c_address_multidevice` | Engineering nuances Claude flagged for human review. | Surface to schematic designer. |
| `unrecoverable_extraction_error` | Claude returned malformed JSON twice in a row. | Surface to a human; inspect raw responses in `.ds2sf-cache/`. |
### Agent calling recipe
```rust
// (Pseudo-Rust for adom-chip-fetcher's caller side.)
fn run_ds2sf(chip_dir: &Path, pdf_override: Option<&Path>) -> ResultDoc {
let mut cmd = Command::new("adom-ds2sf");
cmd.arg("extract").arg(chip_dir).arg("--force").arg("--json-only");
if let Some(p) = pdf_override { cmd.arg("--pdf").arg(p); }
let _ = cmd.status(); // exit code mirrored in result.json
let path = chip_dir.join(format!("{}-extraction.result.json", basename(chip_dir)));
serde_json::from_str(&fs::read_to_string(path).unwrap()).unwrap()
}
let mut tried: HashSet<PathBuf> = HashSet::new();
let mut r = run_ds2sf(chip_dir, None);
tried.insert(r.datasheet_used.clone());
while r.status == "needs_better_pdf" {
// Pull the first try_alternate_pdf hint we haven't already tried.
let next = r.hints.iter()
.filter_map(|h| if let Hint::TryAlternatePdf { candidates, .. } = h { Some(candidates) } else { None })
.flatten()
.find(|c| !tried.contains(*c));
let Some(next) = next else {
// Out of candidates â escalate to human.
log_for_review(&r); break;
};
tried.insert(next.clone());
r = run_ds2sf(chip_dir, Some(next));
}
match r.status.as_str() {
"ok" => {
accept(r.outputs);
// Apply update_upstream_metadata hints (e.g. fix info.json's package).
for h in &r.hints {
if let Hint::UpdateUpstreamMetadata { file, key, extracted, .. } = h {
patch_json(file, key, extracted);
}
}
}
"unrecoverable" => log_for_review(&r),
_ => unreachable!(),
}
```
### Caching behavior under cache-hit
If `<MPN>-extraction.provenance.json` already exists and `--force` is not passed, adom-ds2sf skips the Claude calls entirely and exits with the cached result.json's exit code. Re-running is idempotent.