Skip to content

Calculate purchase quantities

CLI 0.6.14 and MCP 0.2.14 calculate assembly starts and purchase quantities from a reviewed CSV, TSV or XLSX BOM. Your agent supplies the current batch, explicit parent records, make/buy boundaries and quantity allowances. The calculation keeps every source row and asks for clarification when the basis is incomplete.

This runs locally without a key or API request. It produces a calculation for review, not a purchase order, supplier quote or engineering approval. Your host/model still receives the tool output under its own data policy.

Start in a new directory with the synthetic files used in BOM review:

Terminal window
curl -fSLo bom.csv https://trymaglev.com/docs/examples/bom-review/bom.csv
curl -fSLo mapping.json https://trymaglev.com/docs/examples/bom-review/mapping.json
maglev context review-bom bom.csv --mapping mapping.json --json > bom-review.json

This Node.js command creates a plan for two sample products. Its assumptions apply only to this synthetic example. Use the actual batch, relationships and confirmed allowances for your own design.

Terminal window
node --input-type=module <<'JS'
import { readFileSync, writeFileSync } from 'node:fs';
const report = JSON.parse(readFileSync('bom-review.json', 'utf8'));
const plan = {
schemaVersion: 'maglev.bom-plan/1',
artifactSha256: report.artifact.sha256,
mappingSha256: report.mappingSha256,
currentBuild: {
quantity: '2', unit: 'piece', configuration: 'pilot',
confirmation: 'caller_confirmed',
sourceReference: 'Synthetic two-product sample request'
},
totalBuildBasis: null,
nodes: [
{ record: 2, parentRecord: null, kind: 'purchase', purchaseGroup: 'brackets' },
{ record: 3, parentRecord: null, kind: 'purchase', purchaseGroup: 'wire' },
{ record: 4, parentRecord: null, kind: 'purchase', purchaseGroup: 'resistor' }
],
purchaseGroups: [
{ id: 'brackets', yield: '1', extraGoodUnits: '0', increment: '1' },
{ id: 'wire', yield: '1', extraGoodUnits: '0', increment: '0.01' },
{ id: 'resistor', yield: '1', extraGoodUnits: '0', increment: '1' }
]
};
writeFileSync('sample-plan.json', JSON.stringify(plan, null, 2), { flag: 'wx' });
JS
maglev context expand-bom bom.csv --mapping mapping.json --input sample-plan.json --json

The result is calculated_for_review: 4 brackets, 0.7 m of wire, and 0 resistors because the resistor is DNP. The original BOM report still has purchaseQuantity: null; calculated lines are separate. Save output only to a new path so your shell does not overwrite an input before the command starts.

Every source record must appear exactly once in nodes. Use record values from the fresh BOM report, not array positions or guessed part names. In XLSX these are the selected worksheet’s original row numbers.

Field Meaning
artifactSha256, mappingSha256 Exact hashes from review-bom. Changed bytes or mapping invalidate the plan.
currentBuild Current finished-product quantity as an integer string, counting unit piece or set, exact configuration, caller confirmation and source reference. Forecast quantity is not an accepted extra input.
totalBuildBasis null when unused. For active build_total rows, supply { quantity, unit, configuration, sourceReference } matching this current batch. A total exported for another batch needs a corrected source.
parentRecord Explicit parent for per_parent; null for per_product and build_total. The parent’s part identifier must match the literal source parent column.
kind: "assembly" Internally expanded parent with separately counted children. Declare its yield, extraGoodUnits and increment. Parents use discrete piece/set units.
kind: "purchase" Purchased item, including an externally purchased assembly. Supply a purchaseGroup; separately counted children under a purchase node are rejected.
purchaseGroups Explicit purchase-row grouping. Active members must have identical part, revision, configuration, unit, manufacturer part number and description. Matching names alone never create a group.

For example, when record 2 is a made assembly and record 3 is a screw consumed by it:

[
{ "record": 2, "parentRecord": null, "kind": "assembly", "yield": "0.8", "extraGoodUnits": "0", "increment": "1" },
{ "record": 3, "parentRecord": 2, "kind": "purchase", "purchaseGroup": "screws" }
]

This is a node fragment. The source must declare record 2 per-product, record 3 per-parent and the correct parent identifier. The complete plan also needs the screws purchase group and all other source records.

  • per_product multiplies its source quantity by the current finished-product count.
  • per_parent multiplies by the parent’s planned starts, after that parent’s allowance and rounding.
  • build_total uses its source total once, without multiplying by the build size again.
  • Purchase rows are pooled into their explicit groups before applying each group’s allowance and package rounding.

For an assembly or purchase group:

gross = (required good units + extraGoodUnits) / yield
planned quantity = ceiling(gross / increment) × increment

yield is the caller-declared expected good-output fraction, greater than zero and at most one. It is an assumption, not verified factory performance. extraGoodUnits adds an allowance for that assembly or purchase group; group extras apply once after pooling. increment is an explicit start/order multiple. No allowance is silently filled as 0 or 1. An entirely excluded group stays zero even if it has an extra allowance.

All decimal inputs are strings. Arithmetic uses exact fractions; a repeating grossBeforeRounding has a numerator/denominator and decimal: null. Planned quantities are exact decimal strings. Piece/set quantities, extra units and increments must be whole numbers. Fractional material consumption keeps its original unit; there is no unit conversion.

The result is needs_clarification with purchaseLines: null and assemblyStarts: null if any relevant uncertainty remains. Check issues, the original source.issues and their source locations.

  • Cycles, missing parents, mismatched parent names and incomplete record coverage cannot yield a complete total.
  • Selected revision conflicts, incompatible grouped identities, unknown units/population and fractional piece counts need correction.
  • DNP propagates through a made assembly. Other explicitly identified source configurations remain visible as excluded. An absent configuration is an error.
  • Hidden/filtered workbooks, formulas, unmapped columns and incomplete export scope retain their review requirements. Plan flags cannot waive them.
  • Explicit relationships resolve the parser’s repeated-part question. Selected conflicting revisions remain blocked.

The reader’s existing 2 MiB file and 5,000-row bounds apply. Plans are at most 2 MiB; hierarchy depth is at most 64 parent levels; decimals have at most 36 characters and 9 decimal places. Arithmetic reports a limit error instead of truncating. CLI reports are at most 16 MiB; MCP also enforces its smaller 2 MiB response limit.

This does not infer native CAD semantics, allocate stock, select suppliers, verify yield, assign prices, upload files or authorize purchasing. Recheck the source and reviewed plan before passing quantities to the RFQ workflow.

First call review_local_bom with a relative path and mapping inside MAGLEV_TRANSFER_ROOT. Then call expand_local_bom with the same path, mapping and an explicit plan. It rereads the file and checks its hash; it cannot choose another root or silently reuse a stale report. Both tools are read-only and make no API request.