Kern (German for core) is the evolution of Linchpin β from a tool that analyzes to the core the agency's service runs on. The name changed because the role changed: not reports on demand, but the decision kernel every engagement executes through β the QA gate that vetoes bad deliverables, citations to 25 curated sources on every result, staged writeback with rollback, and guided outcomes that always end in a safe human step. Why Kern β
Kern turns a plain-language brief into finished, QA-gated supply-chain deliverables. A Python engine implements the field's established models across 46 agent-routable capabilities β EOQ, safety stock, (s,Q)/(R,S) policies, multi-echelon, simulation, a network digital twin, forecasting, pricing, price intelligence (competitor position), DDMRP, ABC-XYZ, sourcing, supplier segmentation (Kraljic), landed cost, cost-to-serve, S&OP, facility location, multi-facility network design (p-median), DRP, transportation, FEFO, reconciliation, slotting, warehouse layout, vehicle routing, decision tension map (4 sombreros), reconciled replenishment plan and more β and an orchestrator agent drives every one of them end to end with a never-unprotected guarantee (every result is executed or hands you a ready, safe next step) and safe-staging writeback. Each result is grounded in a knowledge graph of 25 curated SCM sources and the codebase itself.
webapp/static/prototype/) talking to the real POST /api/jobs.Give it a brief; it classifies β runs β validates (QA) β delivers. If QA fails, nothing ships.
flowchart LR
A["Brief (+ optional data)"] --> C{"Classify intent"}
C --> I["inventory_optimization"]
C --> P["pricing"]
C --> L["leadership_chain"]
C --> M["...43 more tools"]
I --> Q{"QA gate"}
P --> Q
L --> Q
M --> Q
Q -->|pass| G["Ground in L3 β source + code citations"]
G --> D["Deliverables β Excel Β· report Β· chart + Fuentes"]
Q -->|fail| N["no deliverable"]
Every one of the 46 registered tools below is routed the same way β one register() call wires a capability into the same classify β prepare β run β QA β deliver pipeline, no special-casing. A few, as a sample:
| Capability | Input | Deliverable |
|---|---|---|
π¦ inventory_optimization |
demand CSV/Excel | Excel + report + CSV β forecast β (s,Q)/(R,S) β budget fit |
π² pricing |
price/qty CSV/Excel | Excel + report β elasticity β margin-maximizing price |
π§ leadership_chain |
a brief / scores | radar chart + report β CHAIN leadership profile + directives |
ποΈ warehouse_layout |
params / brief | 3D HTML + layout.json + report β navigable warehouse (building, yard, docks, gates, racks) |
Runs with or without an LLM: an optional LLMProvider (Claude) sharpens routing and the narrative; the deterministic core works on its own. The whole thing is 1100+ tests.
Every capability below is agent-routable β a brief in, a QA-gated deliverable out β through the exact same pipeline as the four examples above. Source of truth: build_default_registry() in scm_agent/tools.py; this table is regenerated by hand from it, so if the two ever disagree, trust the code. See the Capability Expansion Plan for what's still credential-gated (Shopify/Amazon/ERP connectors, voice) rather than agent-routable today.
π The full list, by area (46 tools)
| Area | Tools |
|---|---|
| Demand & classification | abc_xyz Β· forecast Β· whatif |
| Inventory & replenishment | inventory_optimization Β· newsvendor Β· multi_echelon Β· ddmrp Β· simulation Β· digital_twin Β· drp Β· odoo_replenishment (live Odoo ERP read + writeback) Β· excel_replenishment (client planilla read + writeback) Β· hat_tension (Decision Tension Map, 4 sombreros) Β· hat_settlement (Reconciled Replenishment Plan) |
| Inventory control & health | cycle_count Β· reconciliation Β· excess_obsolete Β· markdown_liquidation Β· fefo Β· data_quality |
| Procurement & sourcing | sourcing Β· supplier_management (Kraljic segmentation) Β· landed_cost Β· acceptance_sampling |
| Network & logistics | facility_location Β· network_design (multi-facility p-median) Β· transportation Β· vehicle_routing Β· warehouse_layout Β· slotting Β· queuing Β· scheduling |
| Pricing & finance | pricing Β· price_intelligence (competitor price position, one-shot) Β· price_watch (discovery-assisted, recurring, read-only) Β· financial_kpis Β· cost_to_serve Β· learning_curve |
| Returns, risk & benchmarking | returns Β· risk Β· dea |
| Planning cadence & projects | sop Β· earned_value Β· launch_readiness (campaign launch-date vs lead-time & coverage) |
| Leadership | leadership_chain |
Three cross-cutting guarantees keep the agent safe in production:
- Never-unprotected β every result is
EXECUTEDor carries an executable path: ranked options, a prepared handoff (pre-filled PO / email / count sheet), or an escalation. No dead ends. - Safe-staging writeback β changes are computed as a dry-run changeset, gated by risk tier + time-boxed approval, applied idempotently, and fully auditable /
rollback()-able. The agent never mutates a system of record blindly. - Data protection by default β every upload is validated (size, type, path) and processed in an isolated, auto-purged per-job directory; no secrets are ever committed. Full threat model and controls in SECURITY.md.
Autonomy here is earned, not declared β a tool only moves toward more
EXECUTEDoutcomes as its tracked accuracy clears a threshold (seescm_agent/autonomy.py's T1/T2/T3 tiers). No fixed "% automated" number is claimed; it grows per tool, per client, with evidence.
A registry-based orchestrator: every capability is a Tool with four stages β prepare β run β qa β deliver β that the orchestrator drives, enforcing "QA fails β no deliverable" in one place. Adding a capability is one register() call; no routing edits.
brief ββΆ intent.classify ββΆ registry.get(tool) ββΆ prepare ββΆ run ββΆ QA ββΆ deliver ββΆ JobResult
(rules + optional LLM) any of the 45 registered tools
scm_agent/βtypesΒ·llm(Claude / rules fallback) Β·registryΒ·toolsΒ·intentΒ·orchestratorΒ·knowledge(L3 grounding) Β·guided_bridge(never-unprotected contract viasrc/guided.py)- Entry points β CLI
examples/run_agent.py, HTTPPOST /api/jobs(multipart, with downloadable deliverables), and the live console underwebapp/static/prototype/ - Statuses β
okΒ·needs_clarificationΒ·needs_dataΒ·qa_failedΒ·error
Full reference: scm_agent/README.md. The leadership_chain capability scores a brief against the CHAIN model (Collaborative / Holistic / Adaptable / Influential / Narrative) β an original synthesis, not a reproduction of any single external text.
π Request lifecycle β POST /api/jobs
sequenceDiagram
participant C as Client (console / curl)
participant API as FastAPI (webapp/app.py)
participant O as Orchestrator (scm_agent)
participant T as Tool (prepareβrunβqaβdeliver)
participant KB as L3 knowledge graph
C->>API: multipart: brief, client, params, file
API->>API: validate params JSON Β· sanitize client Β· cap upload 25 MB Β· pin filename
API->>O: run(brief, data_path, overrides, out_dir)
O->>O: intent.classify (rules + optional LLM)
O->>T: registry.get(tool).prepare β run β qa
T->>KB: query citations (chapter β src/ function)
alt QA passes
T-->>O: deliver() writes Excel + report to job dir
O-->>API: JobResult(status=ok, deliverables, citations)
else QA fails
O-->>API: JobResult(status=qa_failed, no deliverable)
end
API-->>C: JSON + /jobs-output/ download URLs
Example response (status: ok):
{
"status": "ok",
"tool": "inventory_optimization",
"confidence": 0.87,
"summary": "12 SKUs Β· $44k budget Β· 3 flagged high-bias Β· (s,Q) for 9, (R,S) for 3.",
"deliverables": {
"report": "/abs/job/inventory_optimization/report.md",
"excel": "/abs/job/inventory_optimization/inventory_plan.xlsx"
},
"download_urls": {
"report": "/jobs-output/tmp09dw516z/inventory_optimization/report.md",
"excel": "/jobs-output/tmp09dw516z/inventory_optimization/inventory_plan.xlsx"
},
"qa_issues": [],
"clarifications": [],
"citations": [
{"concept": "Safety Stock", "source": "SCM knowledge base", "module": "src/safety_stock.py"}
]
}Other statuses return the same envelope with status one of
needs_clarification Β· needs_data Β· qa_failed Β· error and an empty
deliverables map.
Every job is grounded: the orchestrator queries a knowledge graph and attaches citations to each result (the Fuentes shown in the console). Two graphs, one read-only query surface β scm_agent/knowledge.py:
- Domain knowledge graph (
knowledge/scm-books/) β 25 curated SCM sources (forecasting, pricing, revenue management, inventory, operations, logistics, sustainability, leadership, AI in supply chains): ~1,950 concept nodes with source citations. Committed. - Code graph (
graphify-out/) β the codebase itself, built with/graphify. Gitignored (regenerable).
The bridge ties them together: for each cited concept it resolves the src/ module that implements it, so a deliverable cites the concept and the function behind it.
Economic Order Quantity -> src/eoq.py
Safety Stock -> src/safety_stock.py
Cost & Service-Level Optimization -> src/cost_optimization.py
Query it directly: python examples/query_knowledge.py --bridge "newsvendor" Β· --search "fill rate" Β· --explain crostons_method.
The analytical core the agent stands on: a chain of small pure functions, each answering one question with one point of view. Every number is simulation-real β no Node, no build step.
| The question | Engine | The lens it brings |
|---|---|---|
| How much do I order? | eoq.py |
Cost balance β the lot size where ordering cost meets holding cost (+ volume discounts). |
| When do I reorder? | policies.py |
Trigger & risk β forecast + costs β (s,Q)/(R,S): the reorder point and the quantity. |
| How big a buffer? | safety_stock.py |
Uncertainty β zΒ·ΟΒ·βΟ, keyed off forecast error Ο_e, not raw demand spread (the classic mistake). |
| What service do I actually get? | fill_rate.py |
Realized service β fill rate Ξ² (units served), which stays high even when cycle service Ξ± drops. |
| Is more service worth it? | cost_optimization.py |
Economics β the service level / review period that minimizes holding + shortage cost, not a rule of thumb. |
| Spiky or skewed demand? | forecasting.py Β· distributions.py |
Shape-aware β Croston for intermittent, gamma for skew, exactly where the normal model under-stocks. |
| Where to hold stock across the network? | multi_echelon.py |
System view β guaranteed-service placement across stages, not greedy per node. |
| One perishable shot? | newsvendor.py |
Single period β the critical ratio cu/(cu+co). |
| Can't trust the assumptions? | simulation_opt.py |
Empirical β simulate thousands of demand paths, search (s,Q,S) for the real optimum. |
| Is the plan feasible? | constraints.py |
Operational reality β MOQ, case packs, shelf-life, and a budget allocator that trims safety stock to fit. |
| What price maximizes margin? | pricing.py |
Elasticity β per-SKU price sensitivity β the margin-maximizing markup. |
Why this beats a spreadsheet
- Validated, not assumed β closed-form policies are cross-checked against Monte-Carlo simulation (
simulation.py, backorders + lost sales). - Ο_e, not Ο_demand β safety stock keys off forecast error, the only correct dispersion (the #1 inventory mistake in the wild).
- Shape-aware β intermittent (Croston) and skewed (gamma) demand are first-class, where a normal-curve sheet silently stocks out.
- Feasible by construction β MOQ / budget are constraints, so what ships is buildable, not just mathematically optimal.
- Pure & composable β each module is a pure function, the engine validated against reference numeric examples in a 1100+ test suite; the orchestrator chains them without surprises.
The same engine output, read through four lenses in the live dashboard (/):
Sliders recompute the policy live; the agent console (/console) adds the L3 Fuentes β the source concept and the src/ function behind each number.
π Module reference β coverage by topic
Deliverables are grounded across all 25 curated sources in the knowledge graph, not a single reference.
| Topic | Module | Status |
|---|---|---|
| Inventory policies | src/policies.py |
(s,Q), (R,S) |
| EOQ + volume discounts | src/eoq.py |
β |
| Lead time & review period | src/data_loader.py, src/eoq.py |
β CSV + power-of-2 |
| Safety stock | src/safety_stock.py, src/demand_variability.py |
β normal + gamma |
| Simulation | src/simulation.py |
β backorders + lost sales |
| Stochastic lead time | src/risk_period.py, src/policies.py |
β |
| Fill rate | src/fill_rate.py |
β |
| Cost optimization | src/cost_optimization.py |
β |
| Gamma demand | src/distributions.py |
β |
| Multi-echelon GSM | src/multi_echelon.py |
β allocation + simulation |
| Newsvendor | src/newsvendor.py |
β |
| Price optimization | src/pricing.py |
β elasticity / optimal price / markdown |
| Histograms / KDE | src/discrete_demand.py |
β |
| Simulation optimization | src/simulation_opt.py |
β grid R + Ss |
| Batch multi-SKU | src/batch.py |
β |
| Demand forecasting (front-end) | src/forecasting.py |
β MA / SES / Croston + Ο_e |
| Pluggable data sources | src/sources.py |
β CSV / DataFrame / SQL (DB-API) |
| Business constraints | src/constraints.py |
β MOQ / case packs / shelf-life / budget |
| Export | excel_export, powerbi_export |
β |
Key formulas
EOQ β Q* = sqrt(2 k D / h), C* = sqrt(2 k D h)
Safety stock β Ss = z_alpha Β· sigma_d Β· sqrt(tau) Β· (s,Q): Ο = L Β· (R,S): Ο = R + L
Policies β (s,Q): s = dL + Ss, Q = Q* Β· (R,S): S = dL + dR + Ss
Data format & parameters
data/sample_demand.csv:
date,product_id,quantity,unit_cost,lead_time_days
2024-01-01,SKU-A,100,50,7python examples/run_part1_part2.py --product SKU-B --lead-time 2 --service-level 0.90 --simulate| Flag | Meaning |
|---|---|
--holding-cost |
h (per unit/year) |
--order-cost |
k (fixed order cost) |
--lead-time |
L (periods) |
--service-level |
Cycle service level Ξ± |
--periods-per-year |
Converts weekly data to D |
The full chain runs end to end (examples/run_constrained_plan.py):
data source β forecast (Ο_e) β (s,Q)/(R,S) policy β MOQ/case packs β budget fit
src/sources.py src/forecasting.py src/policies.py src/constraints.py
- Pluggable data (
src/sources.py) β CSV, in-memory DataFrame, or any SQL database viaSqlDemandSource(SQLite, Postgres, MySQL). New backends just satisfy theDemandSourceprotocol. - Forecasting (
src/forecasting.py) β MA / SES / Croston, exposing Ο_e, the correct safety-stock dispersion. - Constraints (
src/constraints.py) β MOQ, case packs, shelf-life caps, and a budget allocator that trims safety stock across the portfolio to fit. - Web UI (
webapp/) β a 4-tab planner (Portfolio Β· SKU Detail Β· Budget Planner Β· Forecast Quality) + the live agent console, served by FastAPI over the engine. See webapp/README.md. - Job-fulfillment layer (
jobs/) β turn a client's demand file (any schema) into client-ready Excel + a written report with automated QA. See jobs/README.md.
Project layout
scm_agent/ Orchestrator: brief β classify β tool (45 registered) β QA β deliver
jobs/ Playbooks (one per tool) + intake/QA/deliverables
src/ Core engine (EOQ β simulation optimization β forecasting β pricing β ...)
webapp/ FastAPI dashboard + POST /api/jobs + live agent console (static/prototype/)
examples/ CLI workflows (run_agent, parts 1-4, batch, jobs, plots)
tests/ 1100+ tests: engine (reference numeric examples) + agent + HTTP layer (traversal/upload guards)
data/ Sample demand + pricing
documentation/ Guides: Getting Started, FAQ, methodology, capability-expansion plan
docs/ Design briefs, handoff notes, assets
power-bi/ CSV dataset + M queries + DAX + SETUP.md
.cursor/skills/ Agent skills (Cursor / Claude Code)
.github/workflows/ CI (pytest on 3.11β3.13)
| Document | Content |
|---|---|
| Getting Started | Setup and first run |
| Methodology | Models, assumptions, glossary |
| FAQ | Common questions |
scm_agent/README.md |
The agent reference |
| Security | Threat model, enforced controls, hardening checklist |
| Deployment | Production hardening: env controls, reverse proxy, load notes |
| MCP Server | Selling read-only analysis access to other AI agents: connecting, key issuance, what's exposed |








