Skip to content

Supplier due diligence ​

Due diligence on a new supplier before the first purchase order, decided by rules, a model and a person together: a questionnaire covers the company, what it will supply, its owners and, for software suppliers, security certification; rules check the company against the sanctions list you keep, its declared owners, a country risk list and the contract value; unless they decline, a model reads the supplier's own description of what it will supply; findings and any supplier the model is not sure of go to procurement. Every rule result, model answer and decision is on the run's record. Pack: examples/policies/supplier-due-diligence/.

A pattern for expressing a supplier and third-party risk policy, not compliance guidance: the thresholds, lists, questions and fields are placeholders chosen to make the example run; a real policy comes from the business's own rules. Its model step calls one install, chatgpt (The chatgpt install). The model never screens the company or its owners: the list and the rules do.

The decision it automates ​

Whether to approve the supplier, send it to procurement, or decline it, when the questionnaire is submitted. Only the rules decline: the model can send a supplier the rules approve to procurement, never decline one or approve one the rules sent to procurement.

Data expected ​

  • The supplier as a subject (kind merchant, a business); nothing is read from its data.
  • The questionnaire's answers under submission: legalName, country, category, supplyDescription (what it will supply, in its own words: 20 to 2,000 characters), annualValue (USD), ownersDeclared with ownerName and ownershipPct, and the security answers for software suppliers.
  • The supplier_sanctions_list and supplier_high_risk_countries lists, which the pack creates with a placeholder row each.
  • An install named chatgpt of the platform's chatgpt app, with your OpenAI API key.

Steps and rules ​

StepTypeWhy
collectwait_for_collectionThe supplier-questionnaire flow; software suppliers get the security step.
rulesevaluate_rulesThe supplier-due-diligence rule set under max_severity.
gatebranchrules.outcome == reject goes straight to the decision, without the model; any other supplier goes to supply_check.
supply_checkcall_appdecide through chatgpt on the supplier's description: two questions, answered under supplyCheck.
routebranchrules.outcome == manual_review opens a case, and so does supplyCheck.answers.fits_category.probability under 0.8; supplyCheck.answers.no_data_access.probability of 0.8 or more approves; the rest open a case.
reviewcreate_caseprocurement_review, 5-day SLA.
decideemit_decisionFrom the rules, or the reviewer's decision.

The rule set supplier-due-diligence (useCase: onboarding) uses max_severity: a failed block rule rejects, a failed warn rule sends the run to review, and the weights add up to the score.

RuleTypeSeverity, weightFails when
supplier_sanctions_clearlist lookupblock, 100legalName is on supplier_sanctions_list
supplier_ownership_declaredcomparisonblock, 100ownersDeclared is no
supplier_country_risklist lookupwarn, 30country is on supplier_high_risk_countries
supplier_contract_valuescore thresholdwarn, 20annualValue is above $500,000

The model step ​

supply_check writes the model a sentence (its stateTemplate) from two of the questionnaire's answers, the category the supplier chose and its supplyDescription, each with a literal default, and asks two questions, each phrased so that a yes lets the supplier through:

QuestionAnswerAsksRead by
fits_categoryyes or no, threshold 0.8Does the description fit the category the supplier chose? A hosted service, an app, an integration with your systems or the maintenance of software is software, whatever the supplier chose.route: under 0.8 opens a case
no_data_accessyes or no, threshold 0.8Will the supplier do the work without personal data of your customers or staff and without access to your systems, networks or facilities? A description that says too little to tell is a no.route: 0.8 or more approves; less opens a case

The category decides which questions the supplier answers: a software vendor that picks Services skips the security step, and fits_category catches it. A supplier that will reach personal data or your systems, or a description the model cannot tell from, goes to procurement rather than through (Routing on an answer). The model never declines a supplier, never approves one the rules sent to procurement, and is never asked about sanctions, owners, company registries or politically exposed persons: those stay with the lists and the rules.

What the vendor sees ​

Through the install, OpenAI receives the step's sentence and its two questions: the category and the supplier's description. Nothing else reaches it: not the legal name, the country, the owners, the contract value or the certificate; no document or image reaches a model (Data protection). A supplier the rules decline is never sent. The one-click install calls OpenAI's Responses API with storing off.

The supplier writes the description and may write instructions into it: at worst, an answer the model was talked into lets through a supplier every rule approved, as the rules alone would (Prompt injection).

The chatgpt install ​

A pack never carries an install: its steps call one by name, so the pack declares it, "installs": { "chatgpt": "chatgpt" }, the platform's ChatGPT (OpenAI API). The import reports chatgpt missing (--publish publishes all the same), and the admin console's import result installs it in one click, with a preset configuration (an OpenAI connection through the Responses API, the console's first suggested model, OpenAI's hosts approved) and a sample key in place of yours. Store your OpenAI API key on the install's page (Configuration › Keys › openaiApiKey) before the workflow runs. Through the API, create the install as Installing a model app shows, named chatgpt.

Until you do, the run fails: OpenAI refuses the sample key, so every supplier the rules do not decline fails at supply_check, with no case and no decision. A model call that fails once the key is in does the same: an outage that outlasts the retries, an exhausted quota or a refusal fails the run at supply_check, and so does a workspace without any install named chatgpt. The vendor's answer shows in the invocation record and under the run's app calls; once the call can succeed, replay the run from supply_check (Operate › Runs, Replay from step), and the supplier is not asked to fill in the questionnaire again. To ask Claude or Gemini instead, install that app under a name of your own and name it in the step's app and in the pack's installs: every model app answers decide in the same shape.

What a reviewer sees ​

A procurement_review case with the questionnaire, each rule's result and the model's answers (supplyCheck, each with its probability) in the run context; the model's call is under Vendor checks. An export of the audit trail with its digest serves the audit later.

How to adapt it ​

Ask the model what your procurement policy weighs, such as subcontractors or offshore work, keep each question phrased so that a yes lets the supplier through, and move the 0.8 in route together with the question's threshold. Load the sanctions lists you screen suppliers against into supplier_sanctions_list, or screen through a vendor: install the platform's http-api for it, add a call_app step between collect and rules on submission.legalName and submission.country with outputKey: "companyScreening", and make supplier_sanctions_clear a comparison that passes when the vendor's verdict, such as companyScreening.body.hit, is false (Adding a vendor step). Screen each owner too, add a call_app step that creates the supplier in your ERP through an http-api install for its API once approved, and have your own scheduler start a screening run for every active supplier each year.

Run it ​

bash
pnpm policy:import examples/policies/supplier-due-diligence --publish

The check runs two fixtures against the model stub (scripts/ai-stub.mjs), whose answers a cue word in the supplier's description picks. expect.json registers Polar Supplies Inc., a goods supplier incorporated in Antarctica (the placeholder on the country list), with declared owners: the company is not on the sanctions list and the country-risk rule fails, so the supplier goes to procurement whatever the model says; cued high, the stub answers both questions yes at 0.95, a procurement_review case opens, the check approves it and the run completes with a manual approve. expect-approved.json registers Cascade Packaging Co., which ships boxes to a distribution center in Reno, Nevada: every rule passes, the stub answers both questions yes at 0.95, and the run completes with an automated approve, no case opened.

Released under the Apache-2.0 License.