new

improved

fixed

Timefold Platform

Employee Shift Scheduling

Field Service Routing

Pickup & Delivery Routing

Comparison CSV export, imperial units, employee groups and demand coverage KPIs (ESS), and more

Today, we're announcing version v1.14 of the Timefold Platform and updates to the Timefold models.
This new version of the Timefold Platform comes with these platform improvements:
  • Take comparison results into your own tools with CSV export
    : You can now export a comparison to CSV from its
    Share
    menu. The file contains the visible comparison rows, with a value, difference, and difference-as-percentage column per dataset. The KPI aggregation popover of a comparison now also shows the sum, next to the minimum, maximum, average, and median. The saved comparisons list now also shows which model each comparison was built on. See comparison and saved comparisons for more details.
  • See distances in miles and feet
    : You can now choose how the platform shows distances. Open the profile menu by clicking the cogwheel in the top-right corner of the header, then select
    Units
    and choose one of these options: the system default, metric, or imperial. With imperial units, the platform shows distances in miles and feet. By default, the platform follows your browser's locale, and it remembers your choice in the browser, just like the theme setting.
  • Pick or upload datasets faster when adding a new plan
    : We've redesigned the first step of the New plan dialog. You now pick a dataset from a dropdown that shows each dataset's short description, and the selected demo dataset's description and constraints appear below it. To use your own data, drag and drop your file, or browse for it, directly inside the
    Custom
    option, which takes two steps instead of three. The dialog also has a new
    Cancel
    button. The
    Import
    profile dialog uses the same drop zone, so you can drop an exported profile in as well as browse for it. See New plan and Export and import profiles for more details.
  • More reliable server-sent events
    : The events stream (
    GET …/{id}/events
    ) now closes after it sends the event for the dataset's final status (for datasets submitted without solving, that's
    DATASET_COMPUTED
    ). We also fixed an issue where events for a dataset could stop arriving when another dataset finished. A heartbeat comment every 30 seconds now keeps proxies from closing idle connections. If your client reconnects automatically, treat a close after the final status as the expected end of the stream. See events stream and Connection lifecycle for more details.
  • Filter notification logs by trigger
    : You can now filter the notification logs by trigger, and open a trigger's edit dialog directly from a log's details. The log details now also show the execution duration. See notification logs for more details.
  • Delete experiments and compare model versions on identical settings
    : You can now delete an experiment (preview) from the Experiments list, which also deletes the datasets its scenarios created. You can now leave out the configuration profile of an experiment scenario. The scenario then uses the settings it was originally solved with, which makes it easier to compare model versions on identical settings. See experiment for more details.
  • Find datasets by ID and filter by profile name
    : Paste a full dataset ID into the search bar on the Plans overview to find that dataset directly. The configuration profile filter now offers your existing profile names in a dropdown. See Searching and filtering datasets for more details.
  • See API versions in the model version picker
    : The model version picker now labels each version with its API version, such as v1 or v2, next to the build version. It also warns you when a model approaches the limit of ten parallel versions. See Semantic versioning for more details.
  • A more compact model catalog
    : The model catalog is now a compact tile grid, with each model's maturity badge on its tile. See model catalog for more details.
  • One consistent layout for lists and tables
    : Every list and data table in the platform now uses the same layout, with a toolbar for search and filters, striped rows, and a footer with pagination.
  • Screen readers announce toasts
    : Screen readers now announce toasts, and each toast's dismiss button has an accessible name.
  • Keyboard access to selected notification channels
    : When you select channels for a notification trigger, each selected channel's remove button is now reachable with the keyboard.
  • Expandable sections report their state to assistive technology
    : Expandable sections, such as the advanced termination settings and validation issue groups, now tell assistive technology whether they're expanded.
  • Expired items consistently highlighted
    : The platform now consistently highlights expired API keys, members, invites, and personal access tokens in red.
Next to that, this new version of the Timefold Platform comes with updates to these Timefold Models:
  • Balance rules count only the shifts that match their shift tags
    : If you use more than one balance rule, each rule now balances only the shifts that match its shift tags, and counts each shift once. This lets the solver find schedules that are more balanced for each rule. We have fixed a bug where a shift was counted in every balance rule of its employee, also in rules whose shift tags do not match the shift. A shift that matched more than one rule was also counted once for each matching rule. The soft score of the balance shift count and balance time worked constraints changes for datasets with more than one balance rule. See Balance shift count and Balance time worked for more details.
  • Tutorials to discover modeling concepts step by step
    : We have created a series of lessons designed to help you understand the concepts behind Timefold's Employee Shift Scheduling model, and how to use them to create a schedule that meets your business needs. They are aimed at new users of Timefold, but may also be useful for experienced users who want to deepen their understanding of modeling concepts. They are intended to complement the extensive technical documentation that already exists. Lessons can be viewed by navigating to the Lessons overview. More lessons will follow. See Lessons overview for more details.
  • Choose which kinds of absence count toward absence-aware rules (preview)
    : You can now limit absence awareness to specific kinds of absence, for example only sick leave, by tagging availability and unavailability time spans. Important: this is a breaking change to the preview
    absenceMode
    field.
    absenceMode
    was a plain string (
    "ABSENCE_AWARE"
    or
    "ABSENCE_UNAWARE"
    ) and is now an object, for example
    "absenceMode": { "type": "ABSENCE_AWARE" }
    . Requests that still send the string value must be updated. Omitting
    absenceMode
    still defaults to
    ABSENCE_UNAWARE
    .
    absenceMode
    now also accepts an
    includeDateTimeSpanTags
    field. When
    includeDateTimeSpanTags
    is non-empty, only
    unavailableTimeSpans
    /
    availableTimeSpans
    that share at least one tag with
    includeDateTimeSpanTags
    count toward absence awareness. Spans without a matching tag are treated as if the employee were fully available during them. This lets you scope absence awareness to a specific kind of absence, for example only bridging gaps or scaling limits for
    sick
    leave, while a
    vacation
    -tagged absence still breaks a consecutive-days streak or counts fully against a rolling-window limit. When
    includeDateTimeSpanTags
    is empty or omitted, every span counts, matching the previous behavior. Time spans also get a new
    tags
    field, matched against
    absenceMode.includeDateTimeSpanTags
    , that describes what a span represents, for example, the reason for an absence.
    includeDateTimeSpanTags
    requires
    absenceMode.type
    to be
    ABSENCE_AWARE
    . Absence-aware rules are a preview feature and subject to change. See Upgrade from 1.35.0 to 1.36.0, Consecutive days worked, Minutes between shifts, Minutes worked in a rolling window, Consecutive days off in a rolling window, Consecutive minutes off in a rolling window, and the Employee Shift Scheduling changelog for more details.
  • See how well your hourly demand is staffed with new demand coverage KPIs
    : Schedules driven by hourly demand rules now report how well the demand curve was actually staffed, using three new demand coverage KPIs. All three are measured in person-time, so
    PT2H
    means one employee for two hours, or two employees for one hour:
    hourlyDemandCoveragePercentage
    , the share of the required staffing that was met;
    uncoveredHourlyDemandPersonDuration
    , how much staffing is missing; and
    excessHourlyDemandPersonDuration
    , how much staffing exceeds the maximum demand. Coverage is measured against each demand interval's
    minDemand
    , and excess against its
    maxDemand
    . A KPI that cannot be measured is left out of the
    kpis
    object rather than reported as zero, so a value of
    0
    always means "measured, and nothing is missing". All three are omitted when the dataset defines no hourly demand rules, and the two coverage figures are omitted when no demand interval defines a
    minDemand
    . These are distinct from
    totalDemandPersonSlots
    ,
    coveredDemandPersonSlots
    , and
    uncoveredDemandPersonSlots
    , which describe how well automatically generated shifts blanket the demand curve, before any employee is assigned. See hourly demand rules, demand coverage KPIs, generated shifts, and the Employee Shift Scheduling changelog for more details.
  • Limit the unique shift tags worked per period across the whole schedule (preview)
    : Global
    minimumMaximumShiftsPerPeriod
    rules now support the
    uniqueTagsLimit
    field, which caps how many distinct tags of the given tag types may be worked across all shifts in a period. Until now
    uniqueTagsLimit
    was only available on a contract's
    periodRules
    , where the cap applies per employee, so there was no way to keep a whole operation on a single kind of task for a period. This is for operations that switch every shift over to one variant at a time, rather than limiting the variety any one employee sees. Any number of shifts can be staffed in the period, as long as they all carry the same tag. All the tag types listed in
    includeTagTypes
    share one budget, so listing two tag types with a
    tagsMax
    of 1 permits one distinct tag in total, not one distinct tag of each type. When
    satisfiability
    is
    REQUIRED
    , the
    Unique tags per period not in required range
    hard constraint leaves shifts unassigned rather than exceed
    tagsMax
    . When it is
    PREFERRED
    , the
    Unique tags per period not in preferred range
    soft constraint penalizes each distinct tag above
    tagsMax
    instead, and all shifts can still be assigned.
    uniqueTagsLimit
    on global rules is a preview feature and subject to change. See Limit unique shift tags worked per period and the Employee Shift Scheduling changelog for more details.
  • Better schedules when limiting unique shift tags per period across the schedule
    : The model now uses a new custom move to better satisfy global
    minimumMaximumShiftsPerPeriod
    rules that define a
    uniqueTagsLimit
    . Previously, the model reached the allowed set of tags one shift at a time, so a period that had settled on the wrong tag could only be corrected by unassigning every shift carrying it first, which has a very low likelihood of happening. A new move now switches a whole period over to a different tag in one step, reassigning all the affected shifts together. The move is used automatically when any global rule also defines a
    uniqueTagsLimit
    . See uniqueTagsLimit for more details.
  • Employee groups on shifts (preview)
    :
    employeeGroups
    is a new top-level API that replaces grouping employees through
    commonTagType
    ,
    groupByEmployeeTag
    and
    groupShiftsPerDayLimit
    on employee pairings. Those fields have been removed from employee pairings. We have added a top-level
    employeeGroups
    collection for cases where a set of employees must be considered together as a group rather than individually or as a pair. Each group declares explicit membership, split into
    requiredEmployees
    and
    preferredEmployees
    : preferred members require at least one required member to be present, while required members can work alone but prefer other members of the group to also be present. Employee groups also support
    commonTagType
    , so that all working members of a group must share a concurrent shift with the same tag of that type, and
    groupShiftsPerDayMax
    , capping how many different shift hours the group's members may work on the same day.
    employeeGroups
    is a preview feature and subject to change. See Migrating from 1.35.0 to 1.36.0, Employee groups, and the Employee Shift Scheduling changelog for more details.
  • Shifts ending at midnight no longer count toward the next day in global period rules
    : Global period rules now count a shift ending exactly at midnight only toward the periods it covers, so your period counts match the days your employees actually work. Previously, global period rules with
    periodShiftOverlapKind
    set to
    START_AND_END
    also counted that shift toward the following day's period. For example, a shift from 16:00 to 00:00 counted toward both the period containing its start and the period starting at 00:00. Global period rules now treat a shift's end time as exclusive, consistent with employee period rules, costs rules, and rolling window rules. This applies to global period rules both with and without a specified zone offset. See Global Period Rule and time zones for more details.
  • More reliable server-sent events
    : This model's events stream also gets the improvements described under "More reliable server-sent events" in the Platform section above.
  • Visit dependencies can now be enforced to be scheduled together
    : Previously, even when a visit dependency's
    coordination
    was set to
    SAME_SHIFT
    or
    SAME_VEHICLE
    , the preceding visit could still be scheduled on its own while its dependent visit remained unassigned. The FSR model now allows requiring that the preceding and following visits of a dependency are scheduled together, or not at all, by specifying
    "coordination": "SAME_SHIFT_ENFORCE"
    . When the preceding visit is scheduled, the following visit must be scheduled too, in the same vehicle shift. See Visit dependency coordination for more details.
Example of visit depency improvements
  • Understand how invalid coverage area geometries are repaired
    : When a vehicle's coverage area has invalid geometry, the model repairs it automatically. The documentation now explains how this repair works, including which library performs it. See Repairing invalid coverage area geometries for more details.
  • Configurable proximity radius for grouping co-located visits
    : The
    Prefer grouping co-located visits
    constraint previously only considered two itinerary items co-located if they shared the exact same location. A new
    preferGroupingColocatedVisitsRadiusMeters
    override now lets you configure a proximity radius (in meters) instead, so that nearby-but-not-identical locations (for example, different geocoded units within the same building) are also considered co-located. The default is
    0
    , which preserves the original exact-location behavior, and the radius is capped at a maximum of
    200
    meters. It can be set globally, and overridden per vehicle shift or linked shift via their own
    preferGroupingColocatedVisitsRadiusMeters
    . See Prefer grouping co-located visits for more details.
  • More reliable server-sent events
    : This model's events stream also gets the improvements described under "More reliable server-sent events" in the Platform section above.
  • Require tags justification now names the missing tags
    : The
    RequireTagsJustification
    record has a new field:
    missingTagNames
    . This field lists the names of the tags a visit needs but the assigned vehicle shift does not have. Previously, the justification only showed the count of missing tags, not their names. See upgrade to the latest version page for more details.
  • More reliable server-sent events
    : This model's events stream also gets the improvements described under "More reliable server-sent events" in the Platform section above.
  • End location visualization
    : The end location of a shift was not being properly visualized in the visualization. This is now fixed with a hollow ring in the same color as the rest of the driver's route at the end location. The start location remains a solid circle in the same color as the rest of the driver's route. See visualization for more details.
Please let us know if you have feedback.