app / ds2sf
!

Not installable via adompkg

This app has no published release. adompkg install kyle/ds2sf will not work until a maintainer publishes a tarball with install.sh and uninstall.sh.

See the publishing docs for the package.json schema and tarball layout required to ship this app.

ds2sf

Datasheet → symbol + footprint + provenance JSON.

A small Rust CLI that runs downstream of chip-fetcher: it reads a chip's datasheet PDF and produces the JSON inputs needed by Adom's sym_create MCP plus a footprint metadata file plus a field-level provenance audit trail. Built for both human use and agent-to-agent calling by an upstream automation (chip-fetcher, batch pipelines).

Mirrors the step2glb naming convention.


What it produces

For a chip directory like ~/project/chip-fetcher/library/<MPN>/, ds2sf writes four JSONs:

<MPN>-symbol.extracted.json        # sym_create-shaped (drop-in MCP input)
<MPN>-footprint.extracted.json     # padCount, bodyDimensions, leadDimensions,
                                   # padDescriptions, symbolPinMap, kicad_baseline
<MPN>-extraction.provenance.json   # per-pin {page, table_caption}
                                   # per-dimension {field, value, page, figure_label}
<MPN>-extraction.result.json       # agent-to-agent contract: status + exit_code + hints

The provenance JSON is the audit trail. Pick any pin or any dimension, follow the page field, open the PDF on that page, and confirm the value is visibly there. Same loop for footprint dimensions via figure_label.


How it works

Two focused claude -p calls per datasheet:

  1. Symbol pass — pinout tables, pin types, Adom logical groups (POWER / I2C / GPIO / etc.), per-pin page provenance.
  2. Footprint pass — package outline, recommended land pattern, body + lead dimensions, per-dimension page provenance.

Each pass has its own JSON schema and its own validator. Failures retry once with the validation error fed back to the model. Symbol-pass receives the canonical pin-name → pin-number map for the footprint pass so the two outputs cannot disagree with themselves.

After Claude finishes, ds2sf normalizes the package name against the service-kicad standard library (Package_SO, Package_QFP, Package_DFN_QFN, Package_LQFP, Package_TO_SOT_SMD, Package_DIP, …). When the package matches, downstream tools just pull the .kicad_mod from there. When it doesn't (custom OLGA packages, modules, optical sensors), bodyDimensions + leadDimensions carry the datasheet-extracted values and kicad_baseline is null.


Sample output

Top of <MPN>-symbol.extracted.json (ADS1115IDGSR)

{
  "symbolName": "ADS1115",
  "manufacturer": "Texas Instruments",
  "package": "VSSOP-10",
  "description": "Ultra-small 16-bit sigma-delta ADC with PGA, internal reference, …",
  "category": "ic",
  "referencePrefix": "U",
  "datasheetUrl": "https://www.ti.com/lit/ds/symlink/ads1115.pdf",
  "pins": [
    { "number": "8", "name": "VDD", "type": "power_in",     "group": "POWER",   "description": "…" },
    { "number": "3", "name": "GND", "type": "passive",      "group": "GROUND",  "description": "…" },
    { "number": "9", "name": "SDA", "type": "bidirectional","group": "I2C",     "description": "…" },
    { "number": "4", "name": "AIN0","type": "input",        "group": "ADC",     "description": "…" }
  ],
  "groups": [ { "name": "POWER", "description": "…" }, … ]
}

Top of <MPN>-extraction.provenance.json

{
  "datasheet": {
    "path": "/…/ADS1115IDGSR.pdf",
    "url":  "https://www.ti.com/lit/ds/symlink/ads1115.pdf",
    "sha256": "65231e81…",
    "source_tier": "mfr",
    "source_host": "ti.com/lit",
    "page_count": 57
  },
  "symbol": {
    "pin_provenance": [
      { "pin_number": "1", "pin_name": "ADDR",
        "page": 3, "table_caption": "Table 4-1. Pin Functions: RUG, DYN, and DGS Packages",
        "confidence": "high" }
    ]
  },
  "footprint": {
    "dimension_provenance": [
      { "field": "bodyDimensions.x", "value": 3.1,
        "page": 52, "figure_label": "DGS0010A VSSOP - 1.1 mm max height Package Outline",
        "confidence": "high" }
    ]
  }
}

Agent-to-agent contract

Every invocation writes <MPN>-extraction.result.json and exits with one of three codes:

Exit status Caller action
0 ok Accept the outputs. review_required[] may have informational entries.
2 needs_better_pdf Try one of hints[].candidates and re-call with --pdf <new>.
3 unrecoverable Surface to a human; inspect .ds2sf-cache/ for the raw Claude responses.

hints[] is a tagged-union list:

  • try_alternate_pdf{reason, candidates: PathBuf[]}. ds2sf already ranked the chip-dir's other PDFs; pick the first one not yet tried.
  • update_upstream_metadata{file, key, current, extracted}. e.g. info.json's package disagrees with the datasheet; patch it and re-run.
  • use_datasheet_extracted_footprint{package}. Custom package; downstream footprint authoring should use the captured dimensions.
  • human_review{reason, notes}. Engineering nuance the schematic designer should see.

This means an upstream agent like chip-fetcher can call ds2sf, walk hints[].candidates until it gets status: ok, and accept the extraction without human input.

let mut tried = HashSet::new();
let mut r = run_ds2sf(chip_dir, None);
tried.insert(r.datasheet_used.clone());
while r.status == "needs_better_pdf" {
    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 { break };
    tried.insert(next.clone());
    r = run_ds2sf(chip_dir, Some(next));
}

Full reason / action enums and the calling recipe are in SKILL.md.


CLI

ds2sf extract <CHIP-DIR>     # read PDF, emit symbol + footprint + provenance + result JSONs
ds2sf svg <CHIP-DIR>         # regenerate <MPN>-footprint.authoritative.svg from cached
                             # footprint JSON; back-stamps outputs.footprint_svg onto
                             # an existing <MPN>-extraction.result.json so chipsmith
                             # & other downstream agents can find it via the contract
ds2sf normalize <PACKAGE>    # resolve a package string against service-kicad stdlib (debug)
ds2sf inspect <CHIP-DIR>     # print summary of an existing extraction
ds2sf health                 # probe `claude` CLI + service-kicad reachability
ds2sf install                # drop SKILL.md to ~/.claude/skills/ds2sf/

extract flags: --pdf, --mpn, --manufacturer, --datasheet-url, --source-tier, --out-dir, --model (default claude-opus-4-7), --force, --symbol-only, --footprint-only, --json-only.


Validated chips (initial release)

MPN Package Stdlib Pins Note
ADS1115IDGSR VSSOP-10 Package_SO:MSOP-10_3x3mm_P0.5mm 10 clean
DRV8316RRGFR VQFN-40 (7×5) ❌ custom 40 caught chip-fetcher's info.json lying about package size
VL53L8CX OLGA-16 ❌ custom 17 all 5 muxed pins flagged, thermal pad called out
ESP32-S3-WROOM-1-N4 SMD module ❌ custom 41 castellated pads, boot-strapping pins, PSRAM variant conflicts

Failure-path also verified: feeding the SoC datasheet to a module product correctly returned status: needs_better_pdf with five ranked candidate PDFs in hints[].


Build

cargo build --release
sudo cp target/release/ds2sf /usr/local/bin/
ds2sf install

Or just ./build.sh.


Cost & latency (Haiku 4.5 baseline)

  • ~$0.20–0.30 per chip end-to-end
  • ~2–3 min wall time per chip
  • Anthropic prompt cache keeps the PDF warm across the symbol→footprint calls