skills/dock-door-assignment/SKILL.md
When the user wants to optimize dock door assignments, schedule truck arrivals, or minimize yard congestion. Also use when the user mentions "dock scheduling," "door assignment," "yard management," "truck scheduling," "cross-dock optimization," or "appointment scheduling." For cross-docking operations, see cross-docking. For yard management, see yard-management.
npx skillsauth add kishorkukreja/awesome-supply-chain dock-door-assignmentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an expert in dock door assignment optimization and yard management. Your goal is to help optimize the assignment of inbound/outbound shipments to dock doors to minimize congestion, reduce dwell time, maximize throughput, and improve overall warehouse efficiency.
Before optimizing dock door assignments, understand:
Facility Layout
Operations Profile
Product Characteristics
Current Challenges
Primary Goals:
Key Metrics:
1. Zone-Based Assignment
2. Product-Based Assignment
3. Time-Slotted Assignment
4. Cross-Dock Pairing
Decision Variables:
Parameters:
Objective Function:
Minimize:
α × Σ Σ Σ (d[j,z[i]] × x[i,j,t]) # Travel distance
+ β × Σ Σ Σ (max(0, t - a[i]) × x[i,j,t]) # Waiting time
+ γ × Σ max_truck_overlap[j] # Congestion penalty
where:
α, β, γ = weights for different objectives
Constraints:
# 1. Each truck assigned to exactly one door at one time
for i in trucks:
Σ Σ x[i,j,t] = 1 for all j, t
# 2. Door capacity (trucks per time slot)
for j in doors:
for t in time_slots:
Σ x[i,j,t] ≤ door_capacity[j] for all i
# 3. No overlap (truck occupies door for processing time)
for j in doors:
for t in time_slots:
Σ x[i,j,t'] ≤ 1 for all i, where t' in [t, t+p[i]]
# 4. Truck can't be assigned before arrival
for i in trucks:
for t < a[i]:
Σ x[i,j,t] = 0 for all j
# 5. Staging area capacity
for j in doors:
Σ (volume[i] × x[i,j,t]) ≤ staging_capacity[j] for all i, t
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
def greedy_dock_assignment(trucks, doors, distances, processing_times):
"""
Greedy heuristic for dock door assignment
Assign each truck to the nearest available door
Parameters:
-----------
trucks : list of dict
[{truck_id, arrival_time, destination_zone, volume}, ...]
doors : list of dict
[{door_id, capacity, zone_affinity}, ...]
distances : dict
{(door_id, zone): distance}
processing_times : dict
{truck_id: duration_minutes}
Returns:
--------
Assignment schedule
"""
# Sort trucks by arrival time
trucks_sorted = sorted(trucks, key=lambda x: x['arrival_time'])
# Track door availability (door_id -> next_available_time)
door_availability = {door['door_id']: datetime.min for door in doors}
assignments = []
for truck in trucks_sorted:
truck_id = truck['truck_id']
arrival = truck['arrival_time']
dest_zone = truck['destination_zone']
process_time = processing_times.get(truck_id, 60) # default 60 min
# Find best door
best_door = None
best_score = float('inf')
for door in doors:
door_id = door['door_id']
available_time = door_availability[door_id]
# Can't assign before door is available and truck arrives
start_time = max(arrival, available_time)
# Calculate score: distance + waiting time
distance = distances.get((door_id, dest_zone), 1000)
waiting_time = (start_time - arrival).total_seconds() / 60
score = distance * 1.0 + waiting_time * 0.5
if score < best_score:
best_score = score
best_door = door_id
best_start = start_time
# Assign truck to best door
end_time = best_start + timedelta(minutes=process_time)
door_availability[best_door] = end_time
assignments.append({
'truck_id': truck_id,
'door_id': best_door,
'scheduled_start': best_start,
'scheduled_end': end_time,
'arrival_time': arrival,
'wait_time_min': (best_start - arrival).total_seconds() / 60,
'destination_zone': dest_zone
})
return pd.DataFrame(assignments)
# Example usage
trucks = [
{'truck_id': 'T001', 'arrival_time': datetime(2024, 1, 1, 8, 0),
'destination_zone': 'A', 'volume': 1000},
{'truck_id': 'T002', 'arrival_time': datetime(2024, 1, 1, 8, 15),
'destination_zone': 'B', 'volume': 800},
{'truck_id': 'T003', 'arrival_time': datetime(2024, 1, 1, 8, 30),
'destination_zone': 'A', 'volume': 1200},
{'truck_id': 'T004', 'arrival_time': datetime(2024, 1, 1, 9, 0),
'destination_zone': 'C', 'volume': 900},
]
doors = [
{'door_id': 'D1', 'capacity': 3, 'zone_affinity': 'A'},
{'door_id': 'D2', 'capacity': 3, 'zone_affinity': 'B'},
{'door_id': 'D3', 'capacity': 3, 'zone_affinity': 'C'},
]
distances = {
('D1', 'A'): 50, ('D1', 'B'): 150, ('D1', 'C'): 200,
('D2', 'A'): 150, ('D2', 'B'): 50, ('D2', 'C'): 180,
('D3', 'A'): 200, ('D3', 'B'): 180, ('D3', 'C'): 50,
}
processing_times = {
'T001': 45, 'T002': 60, 'T003': 50, 'T004': 55
}
schedule = greedy_dock_assignment(trucks, doors, distances, processing_times)
print("Dock Assignment Schedule:")
print(schedule[['truck_id', 'door_id', 'scheduled_start', 'wait_time_min']])
from scipy.optimize import linear_sum_assignment
import numpy as np
def hungarian_dock_assignment(trucks, doors, cost_matrix):
"""
Optimal one-to-one assignment using Hungarian algorithm
Use when number of trucks = number of available door slots
Parameters:
-----------
trucks : list
Truck identifiers
doors : list
Door identifiers
cost_matrix : 2D numpy array
cost[i,j] = cost of assigning truck i to door j
Returns:
--------
Optimal assignments
"""
# Solve assignment problem
row_ind, col_ind = linear_sum_assignment(cost_matrix)
assignments = []
total_cost = 0
for i, j in zip(row_ind, col_ind):
assignments.append({
'truck_id': trucks[i],
'door_id': doors[j],
'cost': cost_matrix[i, j]
})
total_cost += cost_matrix[i, j]
return {
'assignments': assignments,
'total_cost': total_cost
}
# Example
trucks = ['T1', 'T2', 'T3', 'T4']
doors = ['D1', 'D2', 'D3', 'D4']
# Cost matrix: distance + penalty
cost_matrix = np.array([
[50, 150, 200, 180], # T1 costs to each door
[150, 50, 180, 160], # T2
[50, 140, 210, 190], # T3
[200, 180, 50, 70], # T4
])
result = hungarian_dock_assignment(trucks, doors, cost_matrix)
print("Optimal Assignment (Hungarian):")
for assignment in result['assignments']:
print(f" {assignment['truck_id']} → {assignment['door_id']} "
f"(cost: {assignment['cost']})")
print(f"Total Cost: {result['total_cost']}")
from pulp import *
import pandas as pd
def optimize_dock_assignment(trucks, doors, time_slots, distances,
processing_times, arrivals):
"""
Comprehensive dock assignment using MIP
Parameters:
-----------
trucks : list
Truck identifiers
doors : list
Door identifiers
time_slots : list
Time slot identifiers (e.g., [0, 1, 2, ...])
distances : dict
{(truck, door): distance_to_zone}
processing_times : dict
{truck: slots_required}
arrivals : dict
{truck: earliest_slot}
Returns:
--------
Optimal assignment with timing
"""
prob = LpProblem("Dock_Assignment", LpMinimize)
# Decision variables
# x[i,j,t] = 1 if truck i assigned to door j starting at time t
x = LpVariable.dicts("assign",
[(i, j, t) for i in trucks
for j in doors
for t in time_slots],
cat='Binary')
# Waiting time variables
wait = LpVariable.dict("wait",
trucks,
lowBound=0,
cat='Continuous')
# Objective: minimize weighted sum of distance and waiting
alpha = 1.0 # distance weight
beta = 0.5 # waiting time weight
prob += (
alpha * lpSum([
distances.get((i, j), 1000) * x[i, j, t]
for i in trucks for j in doors for t in time_slots
]) +
beta * lpSum([wait[i] for i in trucks])
), "Total_Cost"
# Constraints
# 1. Each truck assigned to exactly one door-time combination
for i in trucks:
prob += lpSum([
x[i, j, t] for j in doors for t in time_slots
]) == 1, f"Truck_{i}_Assignment"
# 2. Door capacity: no overlapping assignments
for j in doors:
for t in time_slots:
# Count trucks using this door at this time
prob += lpSum([
x[i, j, t_start]
for i in trucks
for t_start in range(max(0, t - processing_times.get(i, 1) + 1), t + 1)
if t_start in time_slots
]) <= 1, f"Door_{j}_Time_{t}_Capacity"
# 3. Truck can't be assigned before arrival
for i in trucks:
arrival_slot = arrivals.get(i, 0)
for t in time_slots:
if t < arrival_slot:
for j in doors:
prob += x[i, j, t] == 0, f"Truck_{i}_Arrival_Time_{t}"
# 4. Calculate waiting time
for i in trucks:
arrival_slot = arrivals.get(i, 0)
prob += wait[i] >= lpSum([
(t - arrival_slot) * x[i, j, t]
for j in doors for t in time_slots
]), f"Wait_{i}"
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract solution
assignments = []
for i in trucks:
for j in doors:
for t in time_slots:
if x[i, j, t].varValue > 0.5:
assignments.append({
'truck_id': i,
'door_id': j,
'time_slot': t,
'wait_slots': wait[i].varValue if wait[i].varValue else 0
})
return {
'status': LpStatus[prob.status],
'objective_value': value(prob.objective),
'assignments': pd.DataFrame(assignments)
}
# Example
trucks = ['T1', 'T2', 'T3', 'T4', 'T5']
doors = ['D1', 'D2', 'D3']
time_slots = list(range(0, 20)) # 20 time slots (e.g., 30-min each)
# Distance from each truck's destination zone to each door
distances = {
('T1', 'D1'): 50, ('T1', 'D2'): 150, ('T1', 'D3'): 200,
('T2', 'D1'): 150, ('T2', 'D2'): 50, ('T2', 'D3'): 180,
('T3', 'D1'): 50, ('T3', 'D2'): 140, ('T3', 'D3'): 210,
('T4', 'D1'): 200, ('T4', 'D2'): 180, ('T4', 'D3'): 50,
('T5', 'D1'): 100, ('T5', 'D2'): 100, ('T5', 'D3'): 100,
}
# Processing time in time slots (e.g., 2 slots = 1 hour)
processing_times = {'T1': 2, 'T2': 3, 'T3': 2, 'T4': 3, 'T5': 2}
# Arrival times (time slot)
arrivals = {'T1': 0, 'T2': 2, 'T3': 3, 'T4': 5, 'T5': 6}
result = optimize_dock_assignment(
trucks, doors, time_slots, distances, processing_times, arrivals
)
print(f"Optimization Status: {result['status']}")
print(f"Objective Value: {result['objective_value']:.2f}")
print("\nAssignments:")
print(result['assignments'])
def optimize_crossdock_pairing(inbound_trucks, outbound_trucks,
crossdock_items, doors, distances):
"""
Optimize door assignment for cross-docking operations
Match inbound and outbound doors to minimize transfer distance
Parameters:
-----------
inbound_trucks : list of dict
[{truck_id, arrival_time, items: [sku_list]}, ...]
outbound_trucks : list of dict
[{truck_id, departure_time, items: [sku_list]}, ...]
crossdock_items : dict
{inbound_truck: {outbound_truck: [items_to_transfer]}}
doors : dict
{'inbound': [door_list], 'outbound': [door_list]}
distances : dict
{(inbound_door, outbound_door): transfer_distance}
Returns:
--------
Paired door assignments
"""
prob = LpProblem("CrossDock_Pairing", LpMinimize)
inbound_ids = [t['truck_id'] for t in inbound_trucks]
outbound_ids = [t['truck_id'] for t in outbound_trucks]
inbound_doors = doors['inbound']
outbound_doors = doors['outbound']
# Decision variables
# y_in[i,d] = 1 if inbound truck i assigned to door d
y_in = LpVariable.dicts("inbound",
[(i, d) for i in inbound_ids for d in inbound_doors],
cat='Binary')
# y_out[i,d] = 1 if outbound truck i assigned to door d
y_out = LpVariable.dicts("outbound",
[(i, d) for i in outbound_ids for d in outbound_doors],
cat='Binary')
# Flow variables: f[in_door, out_door] = volume transferred
f = LpVariable.dicts("flow",
[(d1, d2) for d1 in inbound_doors for d2 in outbound_doors],
lowBound=0,
cat='Continuous')
# Objective: minimize transfer distance
prob += lpSum([
distances.get((d1, d2), 100) * f[d1, d2]
for d1 in inbound_doors for d2 in outbound_doors
]), "Transfer_Distance"
# Constraints
# Each truck assigned to one door
for i in inbound_ids:
prob += lpSum([y_in[i, d] for d in inbound_doors]) == 1
for i in outbound_ids:
prob += lpSum([y_out[i, d] for d in outbound_doors]) == 1
# Link flow to door assignments
# (Simplified: would need actual crossdock volumes)
for d1 in inbound_doors:
for d2 in outbound_doors:
# Flow limited by door assignments
prob += f[d1, d2] <= 1000, f"Flow_{d1}_{d2}"
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract solution
inbound_assignments = {}
outbound_assignments = {}
for i in inbound_ids:
for d in inbound_doors:
if y_in[i, d].varValue > 0.5:
inbound_assignments[i] = d
for i in outbound_ids:
for d in outbound_doors:
if y_out[i, d].varValue > 0.5:
outbound_assignments[i] = d
flows = {}
for d1 in inbound_doors:
for d2 in outbound_doors:
if f[d1, d2].varValue > 0.01:
flows[(d1, d2)] = f[d1, d2].varValue
return {
'status': LpStatus[prob.status],
'inbound_assignments': inbound_assignments,
'outbound_assignments': outbound_assignments,
'flows': flows,
'total_distance': value(prob.objective)
}
from datetime import datetime, timedelta
class DockAppointmentScheduler:
"""
Manage dock appointment scheduling with time windows
"""
def __init__(self, doors, operating_hours, slot_duration=30):
"""
Initialize scheduler
Parameters:
-----------
doors : list
Available door IDs
operating_hours : dict
{'start': time, 'end': time}
slot_duration : int
Minutes per appointment slot
"""
self.doors = doors
self.operating_hours = operating_hours
self.slot_duration = slot_duration
self.appointments = {} # {(door, datetime): truck_id}
self.truck_schedules = {} # {truck_id: (door, start_time, end_time)}
def generate_time_slots(self, date):
"""Generate available time slots for a date"""
slots = []
current = datetime.combine(date, self.operating_hours['start'])
end = datetime.combine(date, self.operating_hours['end'])
while current < end:
slots.append(current)
current += timedelta(minutes=self.slot_duration)
return slots
def find_available_slots(self, date, duration_minutes, preferred_doors=None):
"""
Find available appointment slots
Parameters:
-----------
date : datetime.date
Target date
duration_minutes : int
Required duration
preferred_doors : list, optional
Preferred door IDs
Returns:
--------
List of available (door, start_time) tuples
"""
time_slots = self.generate_time_slots(date)
slots_needed = int(np.ceil(duration_minutes / self.slot_duration))
available = []
doors_to_check = preferred_doors if preferred_doors else self.doors
for door in doors_to_check:
for i, start_time in enumerate(time_slots[:-slots_needed + 1]):
# Check if all required slots are free
all_free = True
for offset in range(slots_needed):
slot_time = time_slots[i + offset]
if (door, slot_time) in self.appointments:
all_free = False
break
if all_free:
end_time = time_slots[i + slots_needed - 1] + \
timedelta(minutes=self.slot_duration)
available.append({
'door': door,
'start_time': start_time,
'end_time': end_time,
'duration': duration_minutes
})
return available
def book_appointment(self, truck_id, door, start_time, duration_minutes):
"""
Book an appointment
Returns:
--------
Success (bool) and confirmation details
"""
slots_needed = int(np.ceil(duration_minutes / self.slot_duration))
# Check availability
current_slot = start_time
for _ in range(slots_needed):
if (door, current_slot) in self.appointments:
return {
'success': False,
'message': f'Slot {current_slot} on {door} already booked'
}
current_slot += timedelta(minutes=self.slot_duration)
# Book slots
current_slot = start_time
for _ in range(slots_needed):
self.appointments[(door, current_slot)] = truck_id
current_slot += timedelta(minutes=self.slot_duration)
end_time = start_time + timedelta(minutes=duration_minutes)
self.truck_schedules[truck_id] = (door, start_time, end_time)
return {
'success': True,
'truck_id': truck_id,
'door': door,
'start_time': start_time,
'end_time': end_time,
'confirmation': f'{truck_id} booked on {door} from {start_time} to {end_time}'
}
def cancel_appointment(self, truck_id):
"""Cancel an existing appointment"""
if truck_id not in self.truck_schedules:
return {'success': False, 'message': 'Appointment not found'}
door, start_time, end_time = self.truck_schedules[truck_id]
# Remove appointment slots
current_slot = start_time
while current_slot < end_time:
if (door, current_slot) in self.appointments:
del self.appointments[(door, current_slot)]
current_slot += timedelta(minutes=self.slot_duration)
del self.truck_schedules[truck_id]
return {'success': True, 'message': f'Appointment {truck_id} cancelled'}
def get_door_utilization(self, date):
"""Calculate door utilization for a date"""
time_slots = self.generate_time_slots(date)
total_slots = len(time_slots) * len(self.doors)
booked_slots = sum(
1 for (door, slot_time) in self.appointments
if slot_time.date() == date
)
return {
'date': date,
'utilization': (booked_slots / total_slots * 100) if total_slots > 0 else 0,
'booked_slots': booked_slots,
'total_slots': total_slots
}
# Example usage
from datetime import time
scheduler = DockAppointmentScheduler(
doors=['D1', 'D2', 'D3', 'D4'],
operating_hours={'start': time(6, 0), 'end': time(18, 0)},
slot_duration=30
)
# Find available slots for 90-minute appointment
target_date = datetime(2024, 1, 15).date()
available = scheduler.find_available_slots(target_date, 90, preferred_doors=['D1', 'D2'])
print(f"Available slots on {target_date}:")
for slot in available[:5]: # Show first 5
print(f" {slot['door']}: {slot['start_time'].strftime('%H:%M')} - "
f"{slot['end_time'].strftime('%H:%M')}")
# Book appointments
booking1 = scheduler.book_appointment('TRUCK001', 'D1',
datetime(2024, 1, 15, 8, 0), 90)
print(f"\n{booking1['confirmation']}")
booking2 = scheduler.book_appointment('TRUCK002', 'D1',
datetime(2024, 1, 15, 10, 0), 60)
print(booking2['confirmation'])
# Check utilization
util = scheduler.get_door_utilization(target_date)
print(f"\nDoor Utilization: {util['utilization']:.1f}%")
Warehouse Management Systems with Dock Scheduling:
Specialized Yard Management Systems (YMS):
Transportation Management Systems (TMS) with Dock Integration:
# Optimization
from pulp import * # Linear programming
from scipy.optimize import linear_sum_assignment # Hungarian algorithm
from ortools.sat.python import cp_model # Constraint programming
# Scheduling
import schedule # Job scheduling
from datetime import datetime, timedelta
import pandas as pd
# Simulation
import simpy # Discrete event simulation for dock operations
Problem:
Solutions:
Problem:
Solutions:
Problem:
Solutions:
Problem:
Solutions:
Problem:
Solutions:
Problem:
Solutions:
Daily Door Schedule - January 15, 2024:
| Time | D1 (Zone A) | D2 (Zone B) | D3 (Zone C) | D4 (Cross-Dock) | |------|-------------|-------------|-------------|-----------------| | 06:00-07:30 | T101 (Inbound) | T102 (Inbound) | - | T201 (Outbound) | | 07:30-09:00 | T103 (Inbound) | - | T104 (Inbound) | - | | 09:00-10:30 | - | T105 (Inbound) | T106 (Inbound) | T202 (Outbound) | | 10:30-12:00 | T107 (Inbound) | T108 (Inbound) | - | T203 (Outbound) | | 12:00-13:30 | T109 (Inbound) | - | T110 (Inbound) | - | | 13:30-15:00 | - | T111 (Inbound) | - | T204 (Outbound) | | 15:00-16:30 | T112 (Inbound) | T113 (Inbound) | T114 (Inbound) | T205 (Outbound) |
Performance Metrics:
| Metric | Value | Target | Status | |--------|-------|--------|--------| | Door Utilization | 78% | 70-85% | ✓ On Target | | Avg Wait Time | 12 min | <15 min | ✓ On Target | | Detention Events | 2 | <5 | ✓ On Target | | Avg Travel Distance | 285 ft | <300 ft | ✓ On Target | | Trucks Processed | 28 | 25-30 | ✓ On Target |
Assignment Details:
Truck T101:
- Carrier: ABC Freight
- Arrival: 05:45 (15 min early)
- Assigned Door: D1
- Scheduled: 06:00 - 07:30
- Destination Zone: A
- Distance to Zone: 45 ft
- Status: Completed on time
Truck T102:
- Carrier: XYZ Logistics
- Arrival: 06:05 (5 min late)
- Assigned Door: D2
- Scheduled: 06:00 - 07:30
- Destination Zone: B
- Distance to Zone: 52 ft
- Status: Completed with 10 min delay
Optimization Summary:
Recommendations:
If you need more context:
documentation
When the user wants to optimize yard operations, manage trailer parking, or improve dock door utilization. Also use when the user mentions "yard management," "trailer tracking," "yard jockey," "drop trailer program," "trailer pool," "dock scheduling," or "gate management." For cross-dock operations, see cross-docking. For warehouse design, see warehouse-design.
tools
When the user wants to optimize workforce scheduling, create shift plans, or balance labor demand. Also use when the user mentions "staff scheduling," "labor planning," "shift optimization," "crew scheduling," "roster optimization," or "employee scheduling." For task assignment, see task-assignment-problem. For wave planning labor, see wave-planning-optimization.
testing
When the user wants to optimize pick wave planning, schedule warehouse operations, or improve order fulfillment efficiency. Also use when the user mentions "wave management," "batch picking," "pick wave scheduling," "order release optimization," "wave design," or "pick wave strategy." For order batching, see order-batching-optimization. For workforce scheduling, see workforce-scheduling.
testing
When the user wants to optimize warehouse slot assignments, improve pick efficiency, or design warehouse layouts. Also use when the user mentions "slotting optimization," "slot assignment," "ABC slotting," "pick path optimization," "storage location assignment," "warehouse layout optimization," or "forward pick locations." For picker routing, see picker-routing-optimization. For warehouse design, see warehouse-design.