Capacity and headcount optimizer
Linear optimization plus ML balances hiring schedules against output and cost targets.
Finance processPlanBudgetInvoiceCollectPayCloseReportAudit
By Don, DoneThat’s AI coach · updated
A hiring schedule is only a draft when every constraint is cited
A usable headcount optimizer returns a hiring schedule draft that names the capacity, cost, and output constraints it used. If any of those three is missing for a role family, that line stays empty. The model does not invent an FTE. Leaders still own the hire.
Treat the output as a proposed sequence of start dates, role families, and locations, each row pointing back to the inputs that made it feasible. Without those cites, you have a wish list. With them, you have something FP&A and workforce planning can argue about in the same language as the plan.
Planning suites such as Workday, Anaplan, Pigment, and Runway typically hold the ledgers this work depends on: positions, cost centers, demand, and scenario versions. The optimizer is not a replacement for those systems. It is a solver that reads constraints from them and writes a draft back for human acceptance.
The quality bar is simple. A reader who was not in the room should be able to see why a row exists, why a row is blank, and why no row is an approved requisition.
Load cost, capacity, and output before you ask the solver to run
Load three constraint classes before you solve. Cost is the envelope: compensation bands, burden, contractor versus employee mix, and any freeze or cap the budget already committed. Capacity is what you already have: filled seats, known attrition, notice periods, onboarding lag, and hours that are actually available after PTO and non-delivery work. Output is the work the plan is supposed to produce: units, tickets, closes, coverage hours, or another operational measure your forecast already uses.
Do not substitute a guessed productivity rate for a missing output constraint. Inventing how much one FTE produces so the model can fill a blank is the same error as hiring from a missing constraint. The honest result is an empty row and a listed gap.
Pull output targets from the same forecast path you already trust, not from a side spreadsheet. If revenue or volume is rolling, align the hiring window to ML rolling revenue forecast rather than a static annual number that the forecast has already left behind.
Cost constraints should survive a challenge, not only a copy from last year's headcount. If the envelope itself is untested, run it through zero-based budget challenger before you ask a solver to spend it on starts.
Capacity is often the weakest load. HRIS open positions are not the same as productive capacity. A vacant req with no start-date feasibility, or a team already above sustainable utilization, is a constraint, not a green light. If you cannot state remaining capacity in the same units as output, stop. The solver has nothing valid to optimize.
When the three loads disagree (cost allows starts that capacity cannot absorb, or output requires seats the envelope will not fund), the job of the optimizer is to surface infeasibility, not to pick a favorite silently.
Solve, show cites, and keep empty rows empty
Run the linear program, or a mixed-integer variant if start dates and role types are discrete, against the loaded constraints. Machine learning belongs on the edges that are estimates, such as expected attrition or lag-to-productivity, only when those estimates have a documented source. It does not belong in the decision to mint an FTE that no constraint supports.
After the solve, every proposed start should carry cites: which cost line funded it, which capacity residual it consumes, and which output increment it is meant to serve. Rows that lack a cite in any of the three stay empty. Empty is a feature. It tells recruiting and finance there is no defensible hire yet.
Human acceptance is a separate step. A planner or finance partner reviews the cites, rejects rows that smuggle assumptions, and only then promotes accepted rows into the workforce plan or requisition workflow. Until that accept, the schedule is not a hiring plan. Treating the solver output as an offer letter, or as a req that recruiting should open, is a process failure even when the math is clean.
If you need to compare hiring paths rather than a single solve, generate the alternatives as named scenarios first. Natural-language scenario generation is the right place to name a delayed start or an overtime cover before you re-solve. The optimizer still needs the same three constraint classes in each scenario. Changing the story does not license a missing productivity rate.
An illustrative walk-through for a mixed hiring slate
Imagine a finance-owned hiring slate for a delivery org that must hit a stated output target over two quarters, inside a locked cost envelope, with known bench and a published attrition assumption. Role families in scope include existing producers, where historical output per filled seat is recorded, and a new specialist family, where no measured productivity exists yet.
You load cost from the approved envelope, capacity from filled seats plus confirmed departures, and output from the operating forecast. For producers, the solver can propose a start cadence because all three constraints exist. For the specialist family, output per seat is not in the load. The correct return is an empty specialist row plus a cite that names the missing constraint. You do not invent a productivity rate to complete the slate. You do not copy a neighboring team's rate and call it a constraint.
Leaders still decide whether to hire. They may accept the producer cadence, reject a start that collides with a hiring freeze the model was not shown, or commission a measurement plan for the specialist family before any req is opened. If the envelope later tightens, the next move may be reallocation rather than a new solve for starts. That is reallocation agent during cuts territory, not a reason to keep last week's draft as if the constraints had not changed.
Nothing in this walk-through is a measured result. It is the control logic: cite, or leave blank; accept, or do not hire.
What the optimizer must never become
Three failure modes show up as confident-looking schedules.
Hiring from a missing constraint. The model fills a row because a stakeholder knows the team needs people. If cost, capacity, or output is absent, the row must stay empty. Pressure to show a full slate is not a fourth constraint.
Treating the solver as an offer letter. A feasible start date is not a candidate, a band, or an approval. Compensation, legal entity, manager, and leveling still sit with humans and with the systems of record. Pushing solver output straight into recruiting queues creates phantom reqs that finance did not accept.
Inventing a productivity rate. A blank output driver is the most common temptation, because without it the linear program cannot justify new seats. Fabricating throughput so the math closes is worse than an empty row. It launders a guess into a headcount number that looks optimized.
A quieter failure is using the optimizer to hide a decision that already happened. If leadership already committed to a hire, record it as a decision with its own cites. Do not run the solver afterward to manufacture a constraint trail.
Where this work stops, and what still sits with people
The optimizer stops at a cited draft. It does not open reqs, send offers, or change the forecast. People accept or reject rows, then the workforce plan and the financial plan stay in lockstep.
Keep the loop short. Reload constraints when the forecast, the envelope, or capacity changes. Re-solve. Re-cite. Re-accept. A stale schedule with yesterday's cites is as misleading as a missing constraint.
When the honest answer is that you cannot hire yet, publish the empty rows. That is the quality outcome: a hiring schedule draft that cites capacity, cost, and output, or stays empty until it can.
Is this worth automating for you?
Whether this pays back depends on how much time it takes your team today. Most teams estimate that from memory, and the estimate is usually wrong in one direction or the other. This one is rated high effort to implement, so the baseline matters more than usual.
DoneThat reconstructs where the time actually went, with no timers to forget, so you can measure the baseline before committing to a project and check the gain afterward.
Measure the baseline first