
Enterprise Agent Mesh Engineering Guides · 03/12 · AI-Agent Factory
Build a Supply Chain Agent that turns planning-system exceptions into evidence-backed action narratives without asking an LLM to become the optimiser. Quantities, constraints and feasible plans come from deterministic tools; the agent resolves identities, reconciles evidence, explains causal chains and keeps cross-functional actions inside explicit approval boundaries.
This guide adapts Article 3 of The Enterprise Agent Mesh — Building Twelve Production AI Agents on Claude Code. The chapter’s central architectural claim is preserved: the language model works the exception queue around an existing MRP/DRP or optimisation engine; it does not replace that engine.
Reference design, not a client case study. The handbook includes reference-deployment figures, sample thresholds, costs and failure observations. They are retained only where they clarify the design and are explicitly treated as illustrative, not as independently verified Infinity Technologies client results, benchmarks or promises. Notes marked Web-edition qualification identify implementation hardening or corrections checked against current primary documentation on 15 September 2026.
The solver decides quantities. The agent explains why the plan changed, what evidence supports an exception, which options exist, and who is allowed to act.
The Header illustration is the shared governed-agent-platform visual used across this series. It is not a supply-chain product screenshot or a claim about a deployed client topology.
Planning teams already have MRP, DRP, APS and solver outputs. Their operational bottleneck is often the conversion of hundreds of machine-generated exceptions into a short queue of events that a planner can understand, verify and route. The agent therefore sits between planning data and human execution: it classifies exceptions, assembles causal evidence, reconciles conflicting shipment dates and drafts options whose quantities were computed elsewhere.
| Workflow | Primary artifact | Authority boundary |
|---|---|---|
| Exception queue triage | Severity, action class and one-line reason | May reorder an internal queue after evaluation; never suppresses ambiguous or bad data. |
| Supplier lead-time drift | Observed drift signal with window and provenance | Does not rewrite master data automatically. |
| Inbound ETA reconciliation | Reconciled ETA or explicit disagreement set | No averaging of conflicting signals; internal records may be reversible L3 only after gates. |
| Stock-out risk narrative | Causal chain from exposed demand to root supply constraint | Every link must resolve to a deterministic query result. |
| Expedite / de-expedite | Options with solver-backed quantity, timing and premium | System actions are bounded; PO changes belong to Procurement. |
| Disruption monitoring | Event → lanes → in-transit POs → SKUs → customer exposure | Customer-commit communication belongs to Sales. |
The handbook’s reference deployment reports material reductions in triage time, earlier lead-time-drift detection and better surfacing of ETA disagreements. Treat those figures as design motivation, not as guaranteed outcomes. A real rollout must measure planner corrections, missed critical exceptions, false urgency, action reversals and downstream commercial impact.
L0 and L1 cover disruption observations, shortage narratives and recommendations. L2 can prepare bounded operational actions that a named human approves. L3 is reserved for reversible internal changes such as an ETA update or queue re-ranking after the relevant evaluation gates hold. L4 is deliberately absent. The system never gets an “autonomous supply-chain” badge simply because its prose is persuasive.
Four lines are permanent: the Supply Chain Agent does not change a purchase order; it does not change a customer commit date without Sales authority; it does not infer Incoterms, HS codes or country of origin; and it does not invent order quantities. Those boundaries are architectural ownership boundaries in the mesh, not prompt preferences.
The runtime has one orchestrator, narrow subagents and a deterministic optimisation service. The agent layer owns classification, evidence assembly and language. The solver owns constrained quantities. Inter-agent handoffs are events rather than nested agent calls, so Sales, Procurement or Compliance execute their own policy and tool scopes.
NATS: agent.supply.exception_raised
|
v
+--------------------------------------------+
| sc-orchestrator |
| resolve ids -> dispatch -> assemble result |
+------+---------------+-----------+---------+
| | |
v v v
exception- shortage- eta-
triager explainer reconciler
\ | /
\ | /
+-------------+---------+
|
v
deterministic MCP tools
resolve_part / explain_shortage
solve_replenishment / working_days
|
+--------+---------+
| |
v v
evidence ledger event bus
| |
Sales Ops/ProcurementThe handbook also defines disruption-mapper, which maps an external disruption onto affected lanes, shipments, parts and customers, and an edi-mapping-doctor that runs outside the runtime path to propose reviewed mapping changes. The latter is important: a model may help diagnose an EDI mapping defect, but a reviewed translator map remains the executable interpretation of business documents.
For replenishment, the MCP tool wraps OR-Tools/CBC or an equivalent deterministic mathematical-programming service. The model receives a bounded structured result: changed lines, objective value, sensitivity information and an artifact pointer. It does not receive tens of thousands of planning cells and “reason out” a plan. Google’s official OR-Tools MIP example documents CBC through the MPSolver interface; the separation of mathematical optimisation from narrative reasoning is therefore implementable with ordinary, testable software.
Web-edition qualification — duals and optimality. The handbook correctly notes that shadow prices belong to the continuous relaxation rather than the integer solution. Google’s advanced LP documentation describes dual values for continuous LPs. If the MIP solver returns only FEASIBLE, do not label the plan OPTIMAL; preserve the solver status, objective/bound information and any optimality gap. The reference code’s unconditional "status": "OPTIMAL" after accepting both statuses should be treated as an excerpt that needs this correction in a production implementation.
Model routing is workload-shaped. Cheap classifiers handle exception triage and normalized date comparison; higher-capability workers handle long causal chains and disruption narratives; rare adversarial or mapping work can use a stronger model offline. The exact model names and prices in the handbook are platform-reference examples, not a contract for this web edition.
The repository separates invariants, conditional workflows, deterministic domain tools and release evidence. That split matters more than the framework choice.
supply-chain-agent/
.claude-plugin/plugin.json
.mcp.json
CLAUDE.md
agents/
exception-triager.md
shortage-explainer.md
eta-reconciler.md
disruption-mapper.md
edi-mapping-doctor.md
skills/
shortage-narrative/SKILL.md
shortage-narrative/reference.md
expedite-economics/SKILL.md
edi-failure-triage/SKILL.md
hooks/
hooks.json
policy-gate.py
mcp/
planning/server.py
identity/server.py
visibility/server.py
evals/
triage.golden.jsonl
alias.golden.jsonl
faithfulness.rubric.json# CLAUDE.md — web-edition excerpt
## Units
Every quantity carries an explicit uom.
Never convert cases, pallets or eaches yourself.
Call the plant-specific conversion tool.
## Time
Timestamps are explicit instants.
Lead time means working days on the receiving plant calendar.
Use working_days for date arithmetic across shutdowns and holidays.
## Identifiers
Resolve internal SKU, supplier PN, MPN, customer PN, GTIN and free text
through resolve_part before retrieval or planning queries.
## Arithmetic
Do not compute order quantities, safety stock, reorder points or EOQ in prose.
Use solve_replenishment; if the solver is unavailable, stop.
## Boundaries
PO change -> Procurement event.
Customer commit-date impact -> Sales event.
Incoterm / tariff / origin -> Trade Compliance.
## Disclosure
If any source is stale or incomplete, every narrative contains a Data gaps
section naming the source and its as_of timestamp.The handbook chooses EACH as a canonical internal unit and states a default reporting currency for its reference environment. In a reusable implementation, make both organization configuration rather than universal constants. The invariant is not “EUR”; it is “every amount carries an explicit ISO currency code, and mixed currencies are never silently aggregated.” Likewise, a required UoM with a controlled conversion service is the safety property; the canonical UoM is deployment-specific.
The subagent boundary is primarily a capability boundary. Anthropic’s current subagent documentation supports explicit tools and disallowedTools; use both, then enforce sensitive authorization again in the service and hook layers.
---
name: exception-triager
description: Classify one MRP/DRP exception; never solve it.
tools: mcp__planning__get_exception_context, mcp__identity__resolve_part
disallowedTools: Write, Edit, Bash
model: haiku
maxTurns: 4
permissionMode: default
---
1. Resolve all identifiers first.
2. If resolution is ambiguous, emit needs_identity_review and stop.
3. Load one deterministic feature bundle: days of cover, value at risk,
demand-volatility class, customer criticality and source as_of.
4. Emit one schema-constrained verdict.
5. Stale or suspect data is visible as data_quality; never suppress it.The reference thresholds—for example the exact confidence, value-at-risk and stale-hour cutoffs—are policy configuration. Keep them versioned and evaluated, rather than buried in free-form prompt prose.
---
name: shortage-explainer
description: Build an evidence-linked causal chain and planner narrative.
tools: mcp__planning__explain_shortage, mcp__planning__solve_replenishment,
mcp__identity__resolve_part, mcp__corpus__search, Read
disallowedTools: Write, Edit, Bash
model: sonnet
maxTurns: 18
skills: [shortage-narrative, expedite-economics]
---
Every causal claim maps to a link returned by explain_shortage.
Carry source_query and as_of into the artifact.
Unverified reasoning is labelled Hypothesis (unverified) and names
the query that would settle it.
Every quantity comes from a tool result.
Never merge supplier-claimed and carrier-observed dates.The output has a stable grammar: headline, causal chain, solver-backed options and data gaps. That grammar is not presentation polish; it lets the evaluation harness test whether every sentence has evidence and whether stale inputs are disclosed.
The ETA worker compares already-normalised signals rather than interpreting raw carrier payloads. When signals are close enough to be considered consistent, a configured source-precedence policy applies. When they materially disagree, all conflicting signals are returned and disagreement=true. There is no midpoint and no invented precision. Old pings are last_known, not “current.”
The disruption mapper follows explicit links from a disruption event to lanes, shipments, parts and customer exposure; customer communication remains with Sales. The EDI mapping doctor is an offline engineering assistant: it may inspect a rejected transaction, partner implementation guide and current translator map to draft a code diff, but the diff is reviewed and tested before merge. It is never a runtime EDI parser.
shortage-narrative is a reusable house format rather than a permanent system-prompt block. Current Claude Code skills documentation supports forked context and dynamic command injection, but production supply-chain inputs should still cross a typed boundary.
---
name: shortage-narrative
description: Produce a planner-facing shortage narrative with causal provenance.
allowed-tools: mcp__planning__explain_shortage,
mcp__planning__solve_replenishment, Read
user-invocable: true
context: fork
argument-hint: "[sku] [location] [horizon-days]"
---
Headline
What runs out, when, affected demand, explicit UoM and value-at-risk currency.
Chain
One evidence-backed causal link per row, surface -> root.
Every link ends with source_query and as_of.
Options
option | quantity + UoM | cost delta | earliest effect | approver
All quantities and economics come from deterministic tools.
Include "do nothing" with its modelled consequence.
Data gaps
Name every stale or incomplete source. Never omit this section.Web-edition qualification — live data injection. The source skill injects a SQL command containing a location argument. Do not concatenate user/model text into SQL or shell commands in a production adaptation. Prefer a typed read-only tool with server-derived tenant scope and parameterized SQL. Dynamic skill loading is useful; dynamic string interpolation is not an authorization boundary.
The expedite-economics skill carries the procedure for comparing expedite premium against solver-modelled service impact. edi-failure-triage loads translator diagnostics only when a mapping failure exists. This keeps stable workflow contracts small while moving high-volume reference material behind explicit task boundaries.
The integration layer normalises ERP, WMS, TMS, visibility, EDI and solver interfaces into business verbs. The agent should not learn whether one plant is SAP S/4HANA, another Oracle, or a WMS sits behind a local sidecar. Adapter differences belong behind the MCP server.
| Boundary | Representative operations | Control |
|---|---|---|
| ERP / planning source | exception context, stock position, open supply | Read-scoped service identity; immutable as_of and completeness metadata. |
| WMS | on-hand by bin, receipt history | Local sidecar or gateway; explicit plant scope. |
| TMS / visibility | shipment legs, observed signals, bounded expedite flag | Writes separately authorized and idempotent. |
| EDI translator | canonical document, translation errors | Agent consumes canonical JSON; raw syntax remains translator-owned. |
| Supplier commitments | confirmed dates and quantities | Use supported APIs/portals or reviewed human intake; preserve supplier-claimed provenance. |
| Planning solver | solve_replenishment, explain_shortage, working_days | Deterministic computation, validated inputs, artifact-backed output. |
The handbook lists a “scraped session” as one possible supplier-portal integration shape. This web edition does not recommend scraping as a default. Use supported supplier APIs, EDI, portal exports or a reviewed human intake flow according to contract, security and data-use constraints.
{
"mcpServers": {
"erp": {
"type": "http",
"url": "${AGENT_GATEWAY}/erp/mcp",
"headersHelper": "/opt/bin/get-mcp-auth-headers.sh"
},
"visibility": {
"type": "http",
"url": "${AGENT_GATEWAY}/visibility/mcp",
"headersHelper": "/opt/bin/get-mcp-auth-headers.sh"
},
"planning": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory",
"${CLAUDE_PROJECT_DIR}/mcp/planning", "server.py"]
},
"identity": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory",
"${CLAUDE_PROJECT_DIR}/mcp/identity", "server.py"]
}
}
}Web-edition qualification — headersHelper timing. The current Claude Code MCP documentation describes headersHelper as generating headers when a connection is established or re-established, with refresh on authentication failure—not literally before every tool call. Keep request-level authorization, scope validation and any downstream token exchange in the gateway itself. Do not rely on a connection helper alone for per-request policy.
request:
plan_id: PLAN-EXAMPLE
location_id: PLANT-01
sku_group: GROUP-A
horizon_weeks: 13
uom: EA
service_level_target: 0.98
idempotency_key: immutable-logical-operation-key
result:
solver_status: OPTIMAL | FEASIBLE | INFEASIBLE | ERROR
objective:
value: 12345.67
currency: EUR
as_of: 2026-09-15T04:00:00Z
input_completeness: 1.0
lines: [bounded changed lines]
lines_total: 417
artifact_uri: object://sealed-plan/...
optimality_gap: null | 0.012
sensitivity: [continuous-relaxation results with explicit units]Validate UoM and horizon before solving; fail closed on incomplete required inputs; cache against a logical idempotency key plus a canonical input digest; cap result size; store the full plan as an artifact. The language model receives the subset it needs to explain, not the entire optimization matrix.
The hard retrieval problem in supply chain is often not semantic retrieval at all. A physical part may have an internal SKU, supplier part number, manufacturer part number, customer part number, GTIN and several informal names. Embedding similarity over those strings cannot safely decide identity.
part_identifier(
part_uid,
namespace, -- internal_sku | supplier_pn | mpn | customer_pn | gtin | free_text
owner_id, -- supplier/customer where the namespace is scoped
identifier,
identifier_norm,
confidence,
source, -- erp_master | supplier_catalog | inferred | human
verified_by,
valid_from,
valid_to
)resolve_part performs blocking, deterministic features and controlled adjudication before any corpus query or planning call. Effective dating matters because engineering changes and supplier renames can make today’s alias wrong for a historical document. A suspected edge can be retracted; two canonical part identities are never auto-merged by the model.
PostgreSQL’s pg_trgm documentation describes trigram similarity and indexes suitable for a candidate-generation or fuzzy-match stage. Use that as one feature, not as proof of identity. High-confidence auto-resolution should require corroboration from authoritative namespaces and have a measured false-merge rate.
Supplier contracts, SLAs and quality agreements are chunked by clause, preserving heading path, jurisdiction, effective dates and ACL. Supplier email threads are thread-aware text chunks with a contextual header naming supplier, resolved parts and date. Carrier/trade-lane reference material includes implementation guides used primarily for diagnostics.
Hybrid dense + lexical retrieval may be appropriate after identity has been resolved. The handbook labels the lexical branch BM25 while its example SQL elsewhere uses PostgreSQL ts_rank_cd. PostgreSQL’s full-text search documentation describes ts_rank and ts_rank_cd ranking; that is not native BM25. If BM25 is a requirement, deploy an engine or extension that actually implements it and evaluate that implementation rather than relabelling a different ranker.
Every query is rewritten with the resolved part_uid and verified alias set. Dense retrieval answers document semantics; lexical retrieval catches exact clauses and labels; neither is asked to establish product identity. Retrieval metrics should therefore be separated: alias accuracy and false-merge rate for identity; clause recall and ranking quality for corpora; narrative faithfulness for rendering.
The strongest guardrail is not “be careful.” It is that the Supply Chain service principal cannot execute operations owned by Procurement, Sales or Trade Compliance, and a PreToolUse gate independently rejects those shapes.
# Reference policy contract
FORBIDDEN = {
"change_purchase_order": "owned by Procurement",
"set_incoterm": "owned by Trade Compliance",
"set_hs_code": "classification is not model-inferred",
"set_country_of_origin": "origin is not model-inferred"
}
write_request:
max_order_lines: 25
every_quantity_requires_uom: true
customer_commit_change_requires_sales_approval: true
allocation_override_requires_named_approver: trueBlast-radius limits belong in the action gateway or hook, not in a narrative prompt. The same applies to allocation overrides: a named, authenticated approver and an immutable approval reference are properties of an action request, not text the model is trusted to invent.
Verified runtime qualification. Anthropic’s current Agent SDK permission documentation says allowed_tools can pre-approve calls, while disallowed_tools removes capabilities, and calls already approved may never reach can_use_tool. Use PreToolUse for always-on policy enforcement and enforce authorization again in each write service. A callback is useful defense in depth, not the root trust boundary.
Supplier-facing narratives also need a deterministic projection. Customer names, quantities or demand signals that a supplier is not entitled to see are removed by a data service before generation. “Do not mention customer X” is not redaction.
The execution unit is one exception event, not a resident planning assistant with indefinite context. A worker reconstructs only the required state, uses a deterministic logical operation key and writes a complete ledger record before acknowledging delivery.
EXCEPTION_RECEIVED
-> VALIDATE_SCHEMA_AND_SOURCE_FRESHNESS
-> RESOLVE_PART_IDENTITY
-> ATOMIC_JOB_CLAIM(exception_id, plan_version)
-> TRIAGE
-> IF high/critical:
explain_shortage
optional solve_replenishment
schema + provenance validation
-> SEALED_NARRATIVE + ACTION_PROPOSAL
-> LEDGER_COMMIT
-> PUBLISH_DOWNSTREAM_EVENT
-> ACK
redelivery:
same logical key -> reuse sealed artifact / solver plan
ambiguous external write -> reconcile before retryJetStream or another durable bus supplies redelivery, but the business operation still needs application-level idempotency and reconciliation. See the NATS JetStream documentation for durable-consumer and persistence semantics; do not translate “at least once” into “the action happened exactly once.”
The handbook’s budget and latency figures are useful as circuit-breaker examples only. Set turn, time, tool-result-size and cost ceilings from observed workload behavior. A worker that exceeds them should produce an explicit terminal or routed state; it must not silently truncate a causal chain and still emit a recommendation.
A sealed narrative should record at least prompt/model version, planning snapshot or plan version, resolver version, alias-graph revision, relevant conversion/calendar versions, query/provenance identifiers and action-policy version. That is how a reviewer can reproduce why a de-expedite looked reasonable months later without asking a new model to recreate history.
The source defines separate golden sets rather than one “agent accuracy” number. Keep that separation: classification, ETA reconciliation, entity identity, explanation grounding and solver delegation fail differently.
| Dimension | What the test must prove | Failure to make visible |
|---|---|---|
| Triage precision / critical recall | Urgent messages are surfaced without drowning planners in false urgency. | Missed critical exception, false-critical inflation. |
| ETA error and over-precision | Reconciled dates remain calibrated to signal freshness and lane variance. | Exact-looking timestamp unsupported by evidence. |
| Alias resolution | Correct canonical part; extremely low false-merge rate. | Digit transpositions, owner-namespace collisions, stale alias. |
| Explanation faithfulness | Every causal claim resolves to a deterministic tool result. | Missing citation, UoM mismatch, supplier claim presented as observed. |
| Solver delegation | No order quantity or planning arithmetic originates in prose. | Unsourced numeral or model-computed date/quantity. |
| Data-gap disclosure | Stale/incomplete sources are reflected in the artifact. | “No supply” when the supply feed failed. |
The handbook’s target values are reference gates, not claims of current production performance. A deployment should publish the dataset revision, slice coverage and observed error counts with every rate. A 0.2% false-merge ceiling is meaningless if the test set contains no near-miss part numbers.
Where an LLM judge is used, give it the final narrative and the raw tool-result objects, with a constrained schema describing failures such as no_citation, citation_absent, number_not_in_result, uom_mismatch or supplier_claim_as_observed. Validate the judge against human reviewers. Do not ask the judge whether the narrative is “good”; ask whether each claim is supported.
Negative tests belong in the release gate: ambiguous identifiers, one-character part transpositions, unit mismatches, mixed currencies, stale carrier pings, partial feeds, infeasible solver states, duplicated events, unavailable solver, conflicting ETA signals, supplier-provided prompt injection, missing Sales approval and over-blast-radius write attempts.
A supplier says “500”; one system means eaches, another cases of 24. The mitigation is schema-level: no bare quantity, no default UoM, plant-specific conversion via a deterministic tool, and rendering that refuses to print a number without its unit.
A lead time that crosses a supplier holiday and a plant shutdown is not simple date addition. Route date arithmetic through a calendar service with explicit receiving-plant calendar and timezone. Test boundary dates, shutdown intervals and historical calendar revisions.
An empty result is not necessarily “no supply.” Every source adapter must distinguish complete-empty, incomplete, unavailable and stale states. The narrative’s Data gaps section is mandatory whenever an input is not complete and fresh.
A 19-hour-old position cannot be presented as “currently 40 km from Rotterdam.” Freshness is structured metadata that drives a qualifier field; it is not a tone instruction.
A supplier promise can become an ETA, then a de-expedite recommendation, then a green disruption state. Break that chain by keeping supplier-claimed and carrier-observed distinct and by prohibiting a supplier assertion as the sole basis of a risk-reducing action.
If deterministic queries stop at “supplier late,” do not manufacture an engineering-change explanation because it sounds plausible. A hypothesis is labelled unverified and names the specific query needed to establish it.
A solver that found a feasible solution but did not prove optimality must not be narrated as “the optimal plan.” This is a subtle but important failure because the prose layer can turn a technical status omission into a confident business claim. Preserve status and gap fields all the way to the renderer.
Build the alias graph and resolve_part, expose explain_shortage, and write the evidence ledger. Stay L0/L1. The deliverable is a planner-facing shortage narrative that a human corrects; those corrections become the seed evaluation set. Do not add write paths until identity and provenance are boring.
Add the exception triager over a labelled set, ETA reconciliation over the visibility feed and a bounded solve_replenishment wrapper around the existing solver for one SKU group. Add the policy gate and blast-radius limits before any action can be proposed. Ship explanation-faithfulness tests before write authority.
Expand to additional plants, then add supplier-contract retrieval, disruption mapping and the EDI mapping doctor as a reviewed PR bot. Publish customer-risk events to Sales and PO-change requests to Procurement rather than importing their approval scopes. Expect identity resolution and adapter normalization—not prompting—to absorb most of the engineering work.
The sequence is a reference rollout, not a calendar commitment. Promotion up the autonomy ladder requires locally measured evidence, named owners and rollback/reconciliation procedures.
Primary source: Article 3, “The Supply Chain Agent: Exception Narratives Over an Optimiser You Already Own,” plus the shared-platform conventions in The Enterprise Agent Mesh — Building Twelve Production AI Agents on Claude Code, September 2026. This web edition preserves the chapter’s 12-section structure, the separation of solver from language model, the named workers, identity-first retrieval, evidence-linked narrative contract, action boundaries, evaluation dimensions and build sequence.
Primary technical references checked for the web edition: Claude Code subagents, skills, MCP configuration, Agent SDK permissions, Google OR-Tools MIP, OR-Tools advanced LP, PostgreSQL pg_trgm, PostgreSQL full-text ranking, and NATS JetStream.
Web-edition hardening: current headersHelper semantics are described accurately; universal policy is kept out of can_use_tool; SQL interpolation is replaced conceptually with typed parameterized tools; PostgreSQL lexical ranking is not mislabeled as BM25; feasible-versus-optimal solver status is preserved; supplier portal access is treated as a supported-integration/contract question; and all source cost/throughput figures remain illustrative.
This is guide 03/12 for the business-function agents in Infinity Technologies’ AI-Agent Factory hexagonal mesh.
Previous: HR Agent — Effective-Dated, Jurisdiction-Scoped Policy Retrieval.
Next: Procurement Agent — Segregation of Duties Encoded in the Tool Layer. The next guide is forthcoming; no unpublished URL is linked.
For the separate engineering-agent series, see Enterprise Agent Platform Foundation. The two series share platform concerns but represent different agent boundaries.










.png)
.png)
