Job-Shop Environment¶
The job-shop scheduling example is the main cross-method tutorial environment.
It demonstrates the core OptPilot idea: keep the environment boundary stable, then connect very different methods through candidate contracts.
Shared Comparison Setup¶
The runnable job-shop studies are designed as a comparison set. Where the candidate contract allows it, they use the same:
- validation cases:
ft06_small.yamlandla01_tiny.yaml - objective: minimize
normalized_makespan - secondary metrics:
makespan,tardiness, andutilization - budget:
maxTrials: 1 - runtime: local execution with
parallelism: 1
The study file is the binding point. Each study chooses one environment config, one method config, the objective, budget, execution runtime, evidence level, and seed. The validation cases live in each environment config's evaluator.settings.
What It Evaluates¶
A job-shop instance contains jobs, operations, machine assignments, and processing times. A candidate produces either:
- weighted dispatch-rule parameters
- complete schedule solutions
- a generated
dispatch_rule.py - a generated
solver.py
The evaluator simulates or validates the resulting schedule and returns:
makespannormalized_makespantardinessutilizationfeasibleoperation_count
The primary tutorial objective is:
Study objective fragment:
Environment Config Variants¶
The same environment implementation has four reusable config variants.
| Config | Candidate format | Intended methods |
|---|---|---|
environment_rule_parameters.yaml |
parameters |
Dependency-free weighted dispatching rules |
environment_schedule_solution.yaml |
parameters with solutions |
External solvers and policies, including JobShopLib dispatching rules, simulated annealing, OR-Tools CP-SAT, and reinforcement learning |
environment_dispatch_rule.yaml |
files with dispatch_rule.py |
Dispatching rules, LLM code-writing methods, LLM heuristic repositories |
environment_solver_code.yaml |
files with solver.py |
LLM code-writing methods and user-provided solver-code methods |
This is intentional: the problem and metrics stay the same, while the candidate contract changes.
flowchart TB
Problem["Same validation cases\nsame metrics\nsame evaluator package"]
P["Parameters\nweighted dispatch rule"]
S["Parameters\nsolutions by case id"]
D["Files\ndispatch_rule.py"]
C["Files\nsolver.py"]
Problem --> P
Problem --> S
Problem --> D
Problem --> C
P --> M1["fixed-rule-parameters baseline\nschema-general parameter methods"]
S --> M2["JobShopLib dispatching\nsimulated annealing\nOR-Tools\nRL rollout"]
D --> M3["baseline file copy\nOpenAI file editor\nLLM heuristic repositories"]
C --> M4["solver-code writers"]
The environment configs are not method-specific solver adapters. They are candidate contracts for the same evaluation problem.
JobShopLib Method Families¶
JobShopLib exposes several useful job-shop method families. OptPilot connects them on the method side:
| JobShopLib area | What it provides | OptPilot connection |
|---|---|---|
dispatching.rules |
DispatchingRuleSolver and built-in priority rules such as shortest processing time, first-come first-served, most work remaining, and random operation. |
Turnkey job-shop-lib-dispatching-rule method emits schedule-solution candidates. |
metaheuristics |
SimulatedAnnealingSolver, annealing helpers, neighbor generators, and objective helpers. |
Turnkey job-shop-lib-simulated-annealing method emits schedule-solution candidates. |
constraint_programming |
ORToolsSolver for CP-SAT based job-shop solving. |
Turnkey job-shop-lib-ortools-cpsat method emits schedule-solution candidates. |
reinforcement_learning |
Gymnasium-style single-instance and multi-instance graph environments, reward observers, and rollout utilities. | Runnable Stable-Baselines3 method emits schedule-solution candidates. |
The environment does not import JobShopLib and does not know which of these produced a schedule. JobShopLib imports live in examples/methods/..., and each wrapper translates the JobShopLib schedule into the neutral solutions candidate expected by environment_schedule_solution.yaml.
Connect Another JobShopLib Method¶
Use environment_schedule_solution.yaml when the method can produce a complete schedule. The method wrapper should:
- read job-shop case references from
methodContext.references - convert each case payload into the solver's preferred representation
- run the solver, rule, metaheuristic, or policy rollout
- convert the result into
solutions.<case_id>.operations - return a
parameterscandidate withspec: {solutions: ...}
The bundled wrappers share this shape through examples/methods/job_shop_lib_solvers.py:
solutions = solve_job_shop_cases(study_state, lambda: MyJobShopLibSolver(...))
return [{
"candidate_id": "...",
"format": "parameters",
"spec": {"solutions": solutions},
}]
That is the main OptPilot boundary. A CP-SAT model, simulated annealer, dispatching rule, trained RL policy, Gurobi model, or LLM-controlled search can all connect this way as long as the final candidate is a valid schedule solution.
Run The Baselines¶
Parameter baseline:
uv run optpilot validate examples/studies/job_shop_rule_parameters_baseline.yaml
uv run optpilot run examples/studies/job_shop_rule_parameters_baseline.yaml
File dispatch-rule baseline:
uv run optpilot validate examples/studies/job_shop_dispatch_rule_baseline.yaml
uv run optpilot run examples/studies/job_shop_dispatch_rule_baseline.yaml
Solver-code baseline:
uv run optpilot validate examples/studies/job_shop_solver_code_baseline.yaml
uv run optpilot run examples/studies/job_shop_solver_code_baseline.yaml
JobShopLib dispatching rule:
uv sync --extra examples
uv run optpilot validate examples/studies/job_shop_lib_dispatching_rule.yaml
uv run optpilot run examples/studies/job_shop_lib_dispatching_rule.yaml
Simulated annealing:
uv sync --extra examples
uv run optpilot validate examples/studies/job_shop_simulated_annealing.yaml
uv run optpilot run examples/studies/job_shop_simulated_annealing.yaml
OR-Tools CP-SAT:
uv sync --extra examples
uv run optpilot validate examples/studies/job_shop_ortools_cpsat.yaml
uv run optpilot run examples/studies/job_shop_ortools_cpsat.yaml
Reinforcement learning policy rollout:
uv sync --extra examples
uv run optpilot validate examples/studies/job_shop_rl_stable_baselines.yaml
uv run optpilot run examples/studies/job_shop_rl_stable_baselines.yaml
OpenAI-compatible file editor:
uv run optpilot validate examples/studies/job_shop_openai_dispatch_rule.yaml
uv run optpilot run examples/studies/job_shop_openai_dispatch_rule.yaml
Local heuristic-search command:
uv run optpilot validate examples/studies/job_shop_local_heuristic_search.yaml
uv run optpilot run examples/studies/job_shop_local_heuristic_search.yaml
The baseline studies run from a fresh checkout without API keys or provider credentials. The OpenAI-compatible file-editor study is also executable without provider credentials at maxTrials: 1 because it emits the baseline file candidate first. The JobShopLib dispatching-rule, simulated annealing, CP-SAT, and Stable-Baselines RL studies additionally require the optional examples dependency.
Weighted-Rule Parameter Contract¶
environment_rule_parameters.yaml accepts a parameter candidate:
Candidate-contract fragment:
candidate:
format: parameters
parameters:
schema:
remaining_work_weight:
valueType: float
min: -5.0
max: 5.0
processing_time_weight:
valueType: float
min: -5.0
max: 5.0
The evaluator converts these weights into a priority dispatching rule.
Schedule-Solution Contract¶
environment_schedule_solution.yaml accepts complete schedules keyed by validation case id:
Candidate-contract fragment:
For parameters candidates, schema is a map from parameter name to parameter definition. Here solutions is the single top-level parameter. Its value is an object that contains one schedule per validation case. Other environments might define different top-level parameters such as rule, weights, or solver_settings; this environment chooses solutions because a schedule-producing method submits a bundle of finished schedules.
Candidate spec payload fragment produced by a schedule-solving method:
solutions:
ft06_small:
operations:
- job: 0
operation: 0
machine: 0
start: 0
end: 3
la01_tiny:
operations:
- job: 0
operation: 0
machine: 0
start: 0
end: 2
The keys ft06_small and la01_tiny come from the environment config's case ids. The environment also exposes those case files to methods through methodContext.references, so a solver method can solve the exact benchmark set used by the evaluator.
This contract is suitable for any method that produces finished schedules: JobShopLib, OR-Tools, Gurobi, a trained RL policy, or an internal company solver. The environment only validates and scores schedules. It does not know which method or library produced them.
Schedule-producing methods declare the same output shape on their side:
Method compatibility fragment:
accepts:
formats: [parameters]
requires:
context:
- candidate.parameters.schema
produces:
format: parameters
parameters:
schema:
solutions:
valueType: object
properties: {}
The important part is the structural match: the method produces a solutions parameter shaped like the environment's accepted candidate schema. The environment does not need to know whether that schedule came from OR-Tools, JobShopLib simulated annealing, Stable-Baselines, Gurobi, or something else.
Dispatch-Rule File Contract¶
environment_dispatch_rule.yaml accepts one editable file:
Candidate-contract fragment:
The generated file must define:
Higher scores are scheduled first.
Solver-Code File Contract¶
environment_solver_code.yaml accepts one editable file:
Candidate-contract fragment:
The generated file must define:
The evaluator independently validates the returned schedule. A generated solver does not get credit for an infeasible schedule.
Use this file contract when the candidate itself is code. For example, an LLM code-writing method may produce a new solver.py; a JobShopLib wrapper should normally produce schedule solutions instead.
Wrapper Principle¶
The job-shop example is written as a thin wrapper. simulator.py represents the environment-facing scheduling API; evaluator.py is the OptPilot boundary.
For your own environment, follow the same pattern:
- use the existing Python API, CLI, output files, or database
- write a small evaluator wrapper beside it
- define a candidate contract
- keep method code outside the environment
Next: Choose A Method Track¶
After you understand the environment configs, choose the method page that matches the optimizer you want to connect: