From gd-mcp-skills
Cross-channel inventory rebalancing for GoodDay merchants. Identifies SKUs where one Channel (e.g., Wholesale) has unmet demand while another Channel (e.g., eCommerce) at the same Location has excess Available inventory, and vice versa. Recommends or drafts virtual Transfer Orders to rebalance. Action Skill — drafts mutations for human review and submit. Use when the user says: "rebalancing inventory across channels", "cross-channel transfers", "Wholesale demand gaps", "eCommerce stockout risk", "stranded inventory", "channel imbalance", "OHIO agent", "daily inventory operations", "move units between eCommerce and Wholesale", "uncommitted units on Wholesale SOs", "what Transfers should be done today", "run OHIO", "run the rebalance", or "check channel inventory".
How this skill is triggered — by the user, by Claude, or both
Slash command
/gd-mcp-skills:cross-channel-rebalanceThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Multi-channel brands using GoodDay segment inventory by Channel to prevent oversells. But segmentation can strand units — eCommerce might have excess Available units for a slow SKU while Wholesale has an open Sales Order that can't be fulfilled for that same SKU, or vice versa.
Multi-channel brands using GoodDay segment inventory by Channel to prevent oversells. But segmentation can strand units — eCommerce might have excess Available units for a slow SKU while Wholesale has an open Sales Order that can't be fulfilled for that same SKU, or vice versa.
This Skill automates the analysis and drafts virtual Transfer Orders to rebalance inventory across Channels at the same Location. Five sequential steps; each produces a distinct output that feeds the next.
../Configuration — Shared.md — schedule, delivery, output shape, Data Source contract (Section 16), failure handling (Section 12)../Configuration - Cross-Channel Rebalance.md — channel pairs, demand-analysis thresholds, reserved-units policy, transfer execution policy, inbound-PO lookback, slack delivery mode.../Configuration — Merchant Context.md — Section 1 (Channels), Section 2 (Locations), Section 3 (Slack channel destinations), Section 6 (ignore lists).../🖼️ Brand Guidelines.pdf.This Skill describes the business entities each step needs. The concrete mapping — which production MCP tool, verified query, or CSV column populates each entity — lives in ../MCP Tool Catalog.md. When the GoodDay MCP renames a tool or publishes a new verified query, only the catalog changes; this Skill does not.
Session context (merchant id, today's date, channels, locations) comes from the connected MCP's standard surface — no explicit bootstrap call required.
Entities this Skill needs — look each one up in the catalog:
| Step | Entity needed |
|---|---|
| 1 — Wholesale Demand Gaps | Open Wholesale Sales Orders with at least one line item showing uncommitted units > 0; for each, the SO header ship-window dates and Block-level allocation state |
| 1 — SO drill detail | Full SO detail: Blocks, allocation state (isAllocated, allocationDate, inventoryStatus), line items (unitsOrdered, committedUnits, uncommittedUnits, availableUnits, inventoryDisplayStatus) |
| 2 — eCommerce velocity | Trailing-window weekly fulfillment velocity per SKU at the in-scope Location(s) |
| 2 — Channel imbalance scan | SKUs with deficit in one Channel and excess in another (fast first-pass scan) |
| 2 — Inventory positions | Per-SKU rows across all Channels and Locations: On Hand Available, Reserved, Committed, Unsellable, Inbound — used for cross-Channel comparison and $-exposure rendering |
| 3 — Inbound PO coverage | Next inbound PO per flagged SKU with ETA and units; gates transfer recommendations against incoming supply that would cover the gap |
| 4 — Transfer drafting | Mutation: create a virtual Transfer Order (same Location, source Channel → destination Channel), add line items with calculated quantities, leave in draft (per Configuration transfer_mode) |
| 5 — Slack delivery | Post summary via the connected Slack MCP — channel from Merchant Context Section 3 |
Drill links to created Transfer Orders come from each mutation tool's per-row deep_link field — no separate URL composer needed.
Catalog binding may be partial. If the catalog's current binding for the channel-imbalance, item-velocity, or inventory-valuation entities returns VALIDATION_ERROR: not_found, follow ../Configuration — Shared.md Section 12b: surface a routine-specific notice and do not attempt a fallback.
Step 1: Wholesale Demand Gaps → SKUs where Wholesale needs units it doesn't have
Step 2: eCommerce Stockout Risk → SKUs where eCommerce is running low based on velocity
Step 3: Cross-Channel Matching → Pair demand gaps with excess inventory in other Channels
Step 4: Transfer Recommendations → Recommended Transfers with line-item reasoning
Step 5: Summary & Communication → Consolidated output + Slack draft
Goal: Find open Wholesale Sales Orders where demand exceeds available inventory.
Procedure:
Fetch open Wholesale SOs with uncommitted units (catalog entity: "Open Wholesale SOs with uncommitted demand").
For each SO returned, fetch full SO detail (catalog entity: "SO drill detail").
For each SO Block, classify its state:
Case A — Block is Allocated:
For each line item, compare committedUnits vs unitsOrdered. If uncommittedUnits > 0 or inventoryDisplayStatus is "Needs some" or "Needs all", this SKU has a demand gap.
Case B — Block is NOT Allocated but Ship Window is approaching:
Check the SO's shipAfterDate and shipBeforeDate. If the Ship Window starts within ship_window_proximity_days from Configuration, or has already started/passed, treat this as active demand even though the Block isn't formally allocated. The gap is unitsOrdered − availableUnits (where availableUnits is what's in Wholesale at the origin Location).
Side recommendation: When a Block is Unallocated and the Ship Window is imminent, note in the output that the user should consider Allocating the Block in the GoodDay UI so commitment visibility becomes explicit. Allocation is a UI-only action.
For each demand gap, record: SO number, account, block position, SKU, units ordered, committed, uncommitted, gap, origin Location, ship window start/end.
Output: A list of Wholesale demand gaps by SKU at each Location.
Goal: Find eCommerce SKUs projected to stock out within the stockout_horizon_days window.
Procedure:
First-pass fast scan: fetch the channel-imbalance entity from the catalog. This returns SKUs with deficit in one Channel and excess in another. Filter to the configured location_ids and channel_pairs. Quick candidate list.
For deeper analysis on the candidates, fetch eCommerce velocity over velocity_lookback_weeks from Configuration.
For each candidate SKU, fetch current inventory positions across all Channels (catalog entity: "Inventory positions").
Calculate days of supply per SKU at the Location:
daily_velocity = weekly_velocity / 7
days_of_supply = on_hand_available / daily_velocity
If daily_velocity = 0 or the SKU has no fulfillment history, exclude from stockout projection but note in the "Skipped / Incomplete" section.
Flag any SKU where days_of_supply < stockout_horizon_days.
Output: A list of eCommerce stockout risks per SKU per Location.
Goal: For each demand gap from Step 1 and stockout risk from Step 2, find excess inventory in other Channels that could be transferred.
Procedure:
For Wholesale demand gaps: Look at inventory positions across all Channels for the same SKU at the same Location. Check eCommerce (and other configured Channels) for Available units.
Determine "excess" in the source Channel: units Available that are not needed for that Channel's own demand. If velocity data exists, calculate the source Channel's own days-of-supply. Only recommend transferring units that would leave the source Channel with at least stockout_horizon_days of supply.
If include_reserved_in_available is true in Configuration, include Reserved units in the available pool. Otherwise, exclude them and note any Reserved units in the output.
For eCommerce stockout risks: Look at Wholesale (and other configured Channels) for Available units. But don't blindly pull — check whether those units are needed for open Wholesale SOs.
For each SKU, check: are there open Wholesale SOs at this Location that need this SKU? If yes, calculate Wholesale's "excess" as on_hand_available − sum(unitsOrdered on open SO line items for this SKU). Only the positive remainder is available for transfer to eCommerce.
If there are Unallocated Wholesale Blocks with Ship Windows within ship_window_proximity_days, treat those ordered units as spoken for, even if not formally committed.
Check inbound POs: For each SKU with a gap, fetch the next inbound PO (catalog entity: "Inbound PO coverage").
If a PO exists but arrives AFTER the critical date, proceed with the Transfer recommendation and note the PO for context. POs with an undefined ETA method do not count as cover.
Output: Matched transfer opportunities with direction (eCom → WS or WS → eCom), source Channel, destination Channel, Location, units to transfer, reason, inbound PO if any, hold recommendation if PO covers.
Goal: Present clear, actionable Transfer recommendations with line-item reasoning, and optionally draft Transfer Orders.
Procedure:
Section A — Recommended Transfers (Act Now): SKUs where a demand gap exists, no inbound PO will cover it in time, and excess units are available in another Channel.
For each recommendation, include:
Section B — Approaching (Monitor / Likely Soon): SKUs where a Transfer isn't needed yet but will likely be needed in the coming days:
Section C — Skipped / Incomplete:
include_reserved_in_available = falsetransfer_mode)For each recommended Transfer in Section A, draft a virtual Transfer Order:
gd-onhand-ops Routine 2 can pick it upBehavior by transfer_mode:
recommend — output recommendations only; user creates TOs manuallydraft (default) — draft the Transfer Orders in GoodDay for user review before submitexecute — draft and immediately submit. Caution: virtual transfers close instantly on submit; there is no approval gate between submit and ledger impactCatalog binding handles the specific mutation calls. Drill links come from each created TO's per-row deep_link.
Present the created TOs to the user with their numbers and status.
Goal: Produce a consolidated summary and draft a Slack message.
Procedure:
Present the summary to the user with all three sections from Step 4, formatted as tables for quick scanning.
If the user modified or skipped any recommended Transfers, highlight those changes clearly:
Draft a Slack message for the configured channel (from Merchant Context Section 3) using Slack mrkdwn:
📦 *Cross-Channel Rebalance — [Location Name] ([Date])*
Ran the OHIO channel rebalancing analysis for [Channel Pair]. Here's what was proposed and what's on the radar.
*Transfers Proposed*
• [SKU]: [units] [direction] _([reason])_ [modification flag if any]
*On the Radar (Next Few Days)*
• [SKU]: [brief status and why not yet]
*Skipped / Notes*
• [Any data gaps or excluded items]
_[slack_footer from config]_
Note: the Slack summary reports what was proposed (drafted for human review), not auto-executed. Even in transfer_mode = "execute", the framing should make clear that the operator is the source of authority on what shipped.
Post or present the draft per Configuration slack_mode:
draft — show the message to the user and wait for confirmation before postingauto — post immediately after analysis completeseCommerce demand is velocity-based, not order-based. Trailing fulfillment velocity is a proxy. Actual demand may differ due to promotions, seasonality, or marketing campaigns not reflected in history.
Wholesale demand is based on open SO commitments only. No trailing velocity analysis for Wholesale. Recurring reorder patterns not captured in open SOs are not reflected.
Allocation is a UI-only action. This Skill can flag that a Block should be Allocated, but cannot allocate via MCP. Direct the user to the SO detail page in GoodDay.
Reserved units are excluded by default. If the merchant's SOP allows pulling from Reserved for cross-Channel rebalancing, toggle include_reserved_in_available in Configuration.
Virtual transfers close instantly on submit. There is no approval step between submit and ledger impact in execute mode. Default transfer_mode is draft for safety.
npx claudepluginhub gooddaysoftware/gd-mcp-skills-plugin --plugin gd-mcp-skillsCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.