Propose a change
Name Last commit message Last updated
bin Publish 1.0.1 27d ago
docs Accurate hero 27d ago
src Publish source 27d ago
.gitignore Publish source 27d ago
adom-concur-billboard.png name-first hero, fresh from-scratch screenshot at window size 24d ago
adom-concur-hero-v3.png apply editor sheet: name-first hero 24d ago
adom-concur-hero-v4.png bigger name (+20%), smaller logo (-10%) 24d ago
adom-concur.png Accurate hero 27d ago
build.sh Publish source 27d ago
Cargo.lock Publish source 27d ago
Cargo.toml Publish source 27d ago
install.sh Publish 1.0.0 27d ago
LICENSE Add MIT license (open source) 26d ago
package.json normalize open-source: MIT LICENSE + license field + README license 25d ago
page.json point hero -> v4 24d ago
README.md normalize open-source: MIT LICENSE + license field + README license 25d ago
SKILL.md Publish source 27d ago
uninstall.sh Publish 1.0.0 27d ago

concur

Cross-source consensus check for chip libraries.

A small Rust CLI that runs downstream of ds2sf and chip-fetcher: it loads every available source-of-truth for a chip's symbol and footprint (datasheet-extracted, KiCad UL bundle, Fusion 360 EAGLE .lbr, Altium binary), compares them across seven axes, and emits a result.json with status: golden | divergent | unrecoverable plus tagged hints[] so the upstream caller can either re-fetch a suspect library or escalate to a human.

The pipeline:

chip-fetcher  →  ds2sf (status: ok)  →  concur (status: golden)  →  downstream is happy
                                            ↓ divergent
                                       chip-fetcher refetches a lib
                                       OR human reviews

Why this matters

Concur is opinionated about whether a divergence requires upstream work or is safe to ship. Many "disagreements" between sources are known-benign patterns (exposed-pad counted as pin N+1 in one source but not the other, JEDEC-outline-name vs marketing-name, alt-function pin labels, pad-array span misread as body dim). Concur classifies these as variants and ships the dataset with status: golden_with_variants (exit 0) so the upstream caller can move forward and just remember the variants downstream. Real disagreements stay divergent (exit 2).

Real example from this release's smoke tests:

$ concur check ~/project/chip-fetcher/library/ADS1115IDGSR
  ds2sf       — 10 pins, 10 pads, package "VSSOP-10"
  kicad       — 10 pins, 10 pads, footprint "SOT_ADS1115IDYNR_TEX"
  eagle (.lbr) — 10 pins, 10 pads, package "DGS0010A_N"

OK: ADS1115IDGSR — GOLDEN with variants [variants: label_only, stub_pin_names, body_dim_artifact]

What concur figured out:

  • label_only_mismatch — KiCad's footprint name starts with SOT_ because that's TI's UL library prefix convention, but the geometry (pad count, pad layout, pitch) all agrees with EAGLE's DGS0010A_N and ds2sf's VSSOP-10. The package family really is VSSOP. Cosmetic only.
  • stub_symbol_pin_names — the KiCad UL symbol has pin "names" of "1", "2", "3"… instead of real labels. Downstream can use ds2sf's or EAGLE's pin labels.
  • body_dim_measurement_artifact — ds2sf and EAGLE report different body dimensions (5.05×3.10 vs 4.45×2.00). Body dim is courtyard-only, doesn't affect placement; the diff is a measurement-method artifact (lead-tip span vs pad-array span vs body D dim).

All three are flagged but explained, exit 0, chip-fetcher moves forward.

Outputs

<chip-dir>/<MPN>-concur.result.json — the audit + agent contract:

{
  "schema_version": "1",
  "status": "golden_with_variants",
  "exit_code": 0,
  "mpn": "ADS1115IDGSR",
  "summary": "ADS1115IDGSR — GOLDEN with variants [variants: label_only,stub_pin_names,body_dim_artifact]",
  "sources_compared": ["ds2sf","kicad","eagle"],
  "sources_missing":  ["altium"],
  "variants": [
    { "kind": "label_only_mismatch",
      "notes": "ds2sf: VSSOP-10 → family=VSSOP | eagle: DGS0010A_N → family=VSSOP | kicad: SOT_ADS1115IDYNR_TEX → family=SOT" },
    { "kind": "stub_symbol_pin_names",
      "stub_sources": ["kicad"],
      "canonical_sources": ["ds2sf","eagle"] },
    { "kind": "body_dim_measurement_artifact",
      "notes": "ds2sf: 5.05×3.10 mm | eagle: 4.45×2.00 mm" }
  ],
  "axes": [
    { "axis": "pad_count",     "verdict": "agree" },
    { "axis": "pin_names",     "verdict": "disagree",
      "conflicts": ["kicad has stub-only pin names …"] },
    { "axis": "package_family","verdict": "disagree",
      "conflicts": ["Package families disagree across sources: ds2sf=VSSOP, kicad=SOT, eagle=VSSOP"] }
  ],
  "hints": [
    { "action": "ul_symbol_has_stub_names", "source": "kicad", "pin_count": 10,
      "suggestion": "Use ds2sf-extracted symbol JSON or refetch the .kicad_sym from a manufacturer-direct source" }
  ]
}

Status ladder

Status Exit Caller action
golden 0 Ship it, no caveats.
golden_with_variants 0 Ship it. Every disagreement is explained by variants[]. Downstream tools can use the variant list to decide which source to prefer (ds2sf for pin labels when the KiCad symbol has stubs, etc).
divergent 2 Real disagreement. Refetch a library or escalate to a human.
unrecoverable 3 Couldn't parse ≥2 sources.

Variant kinds (v0.3)

Kind When What it means
exposed_pad_variant Pad count diff is exactly 1 One source counts the EP/thermal pad as pin N+1; the other rolls it into the body. EE practice varies; both are correct.
module_extra_pads Pad count diff > 1 (one source has more) KiCad/EAGLE footprint includes mounting/shield/test pads beyond the module datasheet's user-facing pinout.
label_only_mismatch Package family names differ but geometry agrees Naming-convention artifact (e.g. TI's SOT_ prefix on a VSSOP footprint, JEDEC outline DGS0010A → VSSOP, IPC-7351 generic name SOP65P640X120-20N → TSSOP). Cosmetic only.
stub_symbol_pin_names One source's pin names are pin numbers ("1","2"…) UL stub case. Downstream should use a richer source (ds2sf or EAGLE) for labels.
body_dim_measurement_artifact Body dim disagrees but pad geometry agrees Different sources measured "body" differently (lead-tip span vs body D-dim vs pad-array span). Body dim is courtyard-only; doesn't affect placement.
naming_convention_mismatch Pin names differ but every disagreement is a benign convention swap Channel-digit position (OUT11OUT for op-amps and multi-channel parts) or power-pin alias (V+VCC, V-GND).

Comparison axes

Axis What it checks
pad_count Number of pads in the footprint
pad_numbers Set of pad numbers/labels (1..N or A1, A4, B7…)
symbol_pin_count Number of pins in the symbol
pin_names Per-pin name across sources (slash → underscore, case-insensitive). Sources that emit stub names ("1","2"…) are flagged as ul_symbol_has_stub_names hint.
pin_to_pad_map Does pin VDD map to the same pad number across sources?
package_family SOIC / VSSOP / QFN / SOT / etc., with JEDEC outline aliases (DGS0010A → VSSOP, RGE → QFN, RUG → VQFN, …)
body_dims Body x/y in mm, ±0.5 mm tolerance

Agent-to-agent contract

hints[] is a tagged-union list (separate from variants[] — variants explain why a disagreement is benign; hints tell the caller what action to take). v0.3 enriches refetch hints with concrete suggested_sources (priority-ordered) and expected_resolution so chip-fetcher knows where to refetch from AND how to verify the refetch worked.

Action Carries When
refetch_library_source {format, suspect, notes} A specific lib looks wrong; chip-fetcher should try a different upstream.
ul_symbol_has_stub_names {source, pin_count, suggestion} KiCad UL stub case (pin "names" are pin numbers).
accept_with_caveats {caveats} Soft diffs within tolerance.
human_review {reason, notes} No automated repair safe.
source_parse_failed {format, path, error} A file couldn't be parsed at all.

Calling recipe

let r = run_concur(chip_dir);
match r.status.as_str() {
    "golden" => mark_chip_dir_clean(),
    "divergent" => {
        for h in &r.hints {
            match h {
                Hint::RefetchLibrarySource { format, .. } => {
                    refetch_lib_from_alternate_source(format);
                    return run_concur(chip_dir); // re-call after refetch
                }
                Hint::UlSymbolHasStubNames { .. } => {
                    // Replace .kicad_sym from ds2sf JSON via downstream sym_create.
                }
                _ => {}
            }
        }
    }
    "unrecoverable" => log_for_human(&r),
    _ => unreachable!(),
}

CLI

concur check <CHIP-DIR>     # run cross-source check
concur inspect <CHIP-DIR>   # print summary of an existing concur.result.json
concur health               # parser readiness check
concur install              # drop SKILL.md

check flags: --ds2sf-symbol, --ds2sf-footprint, --kicad-sym, --kicad-mod, --eagle, --mpn, --out-dir, --force, --json-only.

Validated chips (v0.3 release — 9-chip suite)

MPN Pkg Status Variants caught Notes
ADS1115IDGSR VSSOP-10 golden_with_variants label_only, stub_pin_names, body_dim_artifact TI's SOT_ prefix on VSSOP footprint; UL symbol stubs; ds2sf body-dim picked up the lead-tip span
DRV8316RRGFR VQFN-40 golden_with_variants ep EP counted as pin 41 by KiCad/EAGLE, omitted by ds2sf
VL53L8CX OLGA-16 golden_with_variants ep, label_only, body_dim_artifact Custom optical LGA; thermal pad EP variant
ESP32-S3-WROOM-1-N4 SMD module golden_with_variants module_extras, body_dim_artifact KiCad has 8 extra shield/test pads beyond the module's 41 castellations
LM358D SOIC-8 golden_with_variants naming_convention OUT11OUT channel-digit + V+VCC, V-GND power-pin aliases
TPS62840YBGR DSBGA-8 golden_with_variants body_dim_artifact Cleanest of the suite; only courtyard body-dim diff
BMI270 LGA-14 golden_with_variants label_only, body_dim_artifact Bosch IMU; EAGLE 7.x .lbr now parses (DTD support)
MSP430G2553IPW20 TSSOP-20 divergent Real bug. KiCad symbol shifts pin functions: ds2sf says pin 14=NC, KiCad says pin 14=P1.6 with 8 alt-functions. Likely wrong sub-variant in UL bundle.
R7FA4M1AB3CFP LQFP-100 divergent Real bug. Pin 1: ds2sf=P108_TMS_SWDIO, KiCad=P400. AVCC0 lands on pad 90 vs pad 88. Wrong sub-variant of the Renesas RA4M1 family.

7/9 pass cleanly (golden_with_variants exit 0). 2/9 are real wrong-variant findings the upstream caller should refetch. Zero false positives in v0.3.

Out of scope (current)

  • Altium .SchLib (symbol-side) parsing. v0.6 added .PcbLib (pads) via the sister altium-pcblib crate; .SchLib pin labels are still pending.
  • Body-thickness comparison (z-dim). Sources don't reliably report this.
  • Tolerance-aware lead/pad-pitch checks beyond raw body dims.

Altium multi-variant selection (v0.7)

Many vendor .PcbLibs ship multiple footprint variants in the same file — for example DRV8316RRGFR carries RGF0040E-IPC_A (41-pad IPC standard) AND RGF0040E-MFG (57-pad manufacturing layout with extra fiducials and test points). The upstream altium-pcblib crate picks one as "primary" by stream order.

If concur naively trusts the primary, it can disagree with kicad+eagle 100% of the time. v0.7 computes the pad-count consensus from already-parsed sources (ds2sf / kicad / eagle) and asks altium-pcblib for the variant whose pad count is closest to the median. Names containing -MFG / _MFG / DEBUG / FIDUCIAL / TEST get a tiebreak penalty so the IPC-standard variant wins when in doubt.

Effect on the benchmark: DRV8316RRGFR was reporting divergent with altium engaged (57 vs 41) → now reports golden_with_variants (41 across all four sources, only EP-counting differs).

Build

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

Or just ./build.sh.

  • ds2sf — datasheet → symbol + footprint + provenance JSON. Upstream of concur.
  • chip-fetcher — pulls the libraries that concur cross-checks.

Contributing & forking — open source under the Adom org

concur is open source under the adom org on the Adom Wiki. The full source lives in this page's repo — open the Files tab, or adompkg install adom/adom-concur and edit the package. Third-party developers are welcome to modify it and contribute back.

Modify it

  • Get the source from the Files tab (or adompkg install adom/adom-concur), make your changes, and rebuild.

Contribute back to Adom — two paths

  1. Pull request (preferred). The wiki runs a PR-per-page flow: propose your change on this page and the maintainer reviews + merges it — no fork needed.

  2. Fork + breadcrumb. Prefer your own fork or add-on? Publish it as your own wiki page, then drop a breadcrumb on this page pointing at your fork so it's discoverable:

    • Read existing trails: GET https://wiki.adom.inc/api/v1/pages/adom-concur/breadcrumbs
    • Attach a breadcrumb from your fork's page targeting this anchor (a short label + your slug).

    The breadcrumb leaves a linked path back here, so Adom's AI can auto-discover your fork and surface it to users — the trail is followable both ways. Your fork stays yours; the original stays discoverable.

License

MIT — © 2026 Adom Industries Inc. Open source; see LICENSE. Modify, fork, and redistribute freely.