Four doors, one Intake
The app, the command line, the HTTP API and the Claude connector are four ways into the same product — not four products. Same readers, same resolution, same contract, same installation: a decision made in the app is already in force when Claude analyses the next file.
What does not change from one door to the next
The file is read by the same engine, lines are resolved by the same rules, and the result leaves in the same adesio.bom.canonical/v1 contract. No door ever claims to have found a part: found means the file states it. One asymmetry is deliberate — the CLI applies no operator decisions, because a figure it prints is about what the tool reads, not about what somebody confirmed.
The app
For dropping a file and looking at it.
Drag a BOM onto the home page. The report opens, you correct the column roles where the engine got them wrong, you save the reading as a named format — and the next file of that shape is recognised without a question. Lines waiting on a decision collect in the review queue, one card per part rather than per line.
It is the only door where the confirm buttons exist: a downloaded report shows them inert, because there is no longer a server to talk to.
The command line
For processing a file, or a whole folder, without opening a browser.
It produces exactly the same deliverables as the app: the self-contained report, the canonical JSON, the CSVs and the search worklist. It applies no operator decisions and reads no learned formats — what it measures is what the tool understands on its own.
npm install # one file — report, canonical JSON, CSV, and the search worklist npm run analyze -- my-bom.xlsx \ -o report.html --canonical canonical.json --csv bom.csv --queries queries.csv # a sheet by name, an encoding the file lied about, a customer profile npm run analyze -- my-bom.xlsx --sheet "BOM" --profile analyzer/profiles/cadence-atdm.json # a whole folder, twice: pass 1 learns a format per shape, pass 2 re-reads with it npm run corpus-run -- --dir ./boms
The HTTP API
For calling Intake from your own system.
The table below is rendered from the routing table itself, the one openapi.json comes from. An undeclared route is therefore invisible here and unreachable there, and a declared one necessarily appears — the document cannot misdescribe what the server does.
| Method | Path | What it does | Returns |
|---|---|---|---|
| POST | /api/analyze | Analyse one BOM file (multipart `file`) and write its artefacts. Answers the report summary, or the reason the file was refused. | json |
| POST | /api/reports/{id}/reanalyze | Re-read the SAME stored bytes with corrections applied — an encoding, a sheet, a header row, column roles. Corrections accumulate across calls. | json |
| POST | /api/reports/{id}/decisions | Accept, reject or revoke a candidate part for the line’s PART. Keyed on the customer’s part code, so it answers every line that part appears on. | json |
| POST | /api/reports/{id}/quote | Price the report’s already-resolved lines (no re-upload, no re-read of the file) against Octopart’s public prices and return a summary. Rate-limited. 404 when the report is not this caller’s, the add-on is not configured, or `QUOTE_WEB_ENABLED` is off. | json |
| POST | /api/reports/{id}/quote-email | Ask for the report’s chiffrage by mail (D2: only a confirmation LINK is sent now, never the attachment). Spends nothing from the discovery cap yet — `confirmQuoteEmail` does, once the address is verified. Rate-limited. | json |
| GET | /api/decisions | Every decision recorded for this client, accepts and rejects alike. | json |
| GET | /api/reports | Reports held on this installation, newest first. | json |
| GET | /api/profiles | Customer profiles available to attach to an analysis. | json |
| GET | /api/formats | Learned format profiles: what this installation recognises by structure. | json |
| POST | /api/formats | Save what an operator settled on a report as a named, reusable format. | json |
| POST | /api/reports/{id}/confirm-format | An Adesio OPERATOR confirms the detected format this report was read with, for every later file of the same shape — allowed on a public instance, operator tokens only. | json |
| DELETE | /api/formats/{slug} | Forget a learned format. | json |
| GET | /api/reports/{id} | One report’s summary: coverage, KPIs, the format that was applied. | json |
| GET | /api/reports/{id}.{artifact} | One artefact of a report: `canonical.json` is the handoff document (adesio.bom.canonical/v1), `html` the self-contained report, `csv` the flat BOM, `queries.csv` the search worklist, `lookups.csv` the distinct PARTS a supplier lookup would be asked about (the figure a per-part bill is counted on), `json` the internal dump. | mixed |
| GET | /api/schema | The JSON Schema of the canonical document — served so a consumer can validate against the exact version this installation emits. | json |
| GET | /api/openapi.json | This description, as an OpenAPI 3.1 document. | json |
| POST | /api/quote | Analyse one BOM attachment in memory and answer an instant quote preview (best price / lead time / stock, an XLSX and an email). Bearer `QUOTE_API_TOKEN`. With a `reply_to` the Apps Script has verified (its `REPLY_TO_SENDER` switch), answers `status: reply` — what to send that sender, and an alert for the owner when the reply is pending — instead of the owner's quote. 404 when this installation has no quote add-on configured. | json |
| GET | /api/quote/deliveries | Confirmed quotes waiting to be sent, each claimed for a 10-minute lease. Bearer `QUOTE_API_TOKEN`. | json |
| POST | /api/quote/deliveries/{deliveryId}/ack | The script sent it: forget the delivery. Bearer `QUOTE_API_TOKEN`. | json |
| GET | /health | Liveness probe: 200 whenever the process is up, whatever else is configured. Use this one on Cloud Run — it reserves paths ending in `z`, so `/healthz` 404s there. | json |
| POST | /api/invitations | Ask to be invited when Intake goes live. Stores an address and the moment it was given, nothing else. Rate-limited: it is public and appends to a file. | json |
| POST | /api/session | Exchange a client token for a browser session cookie. The token itself is what authenticates; this only moves it into an HttpOnly cookie so a browser can carry it. Rate-limited: it is public and does cryptographic work. | json |
| DELETE | /api/session | Clear the browser session. The token stays valid — revoke it with the CLI to withdraw it for good. | json |
| GET | /api/me | The identity this request carries: client id, token label, and how it was presented. The cheapest way for an integrator to check a token works. | json |
The contract schema is served at /api/schema, the OpenAPI description at /api/openapi.json. HEAD answers like GET; a verb that does not exist on a path that does returns 405 with an Allow header, not 404.
The Claude connector
So Claude reads your BOMs, with the installation's memory.
An MCP server over stdio. Claude opens the same installation the web app uses: same learned formats, same manufacturer aliases, same catalog, same decisions. A part confirmed in the app is already settled the next time round. No tool ever returns a whole BOM — every listing is paginated, and the full line is a second call.
The tools it exposes
- analyze_bom
- Reads a BOM from this machine and returns its coverage, counters and report id.
- list_reports
- Reports this installation holds, with their file name and coverage.
- get_coverage
- One report's counters, named so they cannot be flattened into “resolved / unresolved”.
- list_lines
- A page of lines, narrowed by resolution or by why it needs review.
- get_line
- The full canonical record of one line: identity and its basis, candidates, value, package.
- search_queries
- Lines the file describes but never names, as deduplicated search queries.
- lookup_worklist
- The distinct parts a supplier lookup would be asked about — the figure a per-part bill is counted on.
- review_queue
- Every part waiting on a decision, across all reports, grouped by part.
- record_decision
- WRITES. Records that a part IS the one on a line, is NOT, or undoes a decision.
Declare it in your Claude client's MCP configuration:
{
"mcpServers": {
"adesio-intake": {
"command": "npm",
"args": ["run", "--silent", "mcp", "-w", "analyzer"],
"cwd": "/path/to/bom-analyzer"
}
}
}
This page describes what works today. What does not exist yet is marked as such on the system map.