An explainable workforce scheduling toolkit for developers building AI-assisted operations software.
RosterSpec lets AI generate or modify scheduling scenarios while keeping validation, incremental replanning, explanations, and repair verification deterministic.
It does not merely suggest fixes. It applies, validates, and rejects unsafe repairs.
Public alpha: the core contracts are tested and versioned; product breadth and performance limits are still evolving. Do not use it as a legal, healthcare, or labor-compliance system.
Watch the cursor-guided walkthrough, then run the same production-build flow locally below. The
recording harness is isolated in apps/playground/demo, so none of its custom cursor code ships in
the playground bundle.
uv sync --locked --group dev
uv run rosterspec --version
uv run rosterspec doctor examples/hospital-ward/infeasible.jsonFor local AI-agent integration, install the optional MCP adapter and run its stdio entry point:
uv sync --locked --extra mcp
uv run --locked --extra mcp rosterspec-mcpSee the Codex and Claude MCP example for configuration and the stable-code-only correction workflow.
The repository pins Python, Node.js, pnpm, and uv with mise. Start both the API and playground from the repository root:
mise install
mise run setup
mise run devThe playground is available at http://127.0.0.1:3000 and the API at
http://127.0.0.1:8000. Run mise tasks to list the remaining development commands.
The container stack exposes the API through a shared Nginx rate-limit boundary. CP-SAT work runs in disposable resource-limited worker processes. Doctor responses are cached in memory for up to 60 seconds, so derived scenario information may be retained for that period.
For a containerized evaluation environment instead, run:
docker compose up --buildfrom rosterspec import Engine, Problem
problem = Problem.from_json("examples/support-center/baseline.json")
engine = Engine(
random_seed=42,
reproducible=True,
)
doctor_report = engine.doctor(problem)
if doctor_report.can_solve:
result = engine.solve(problem)
print(result.explanation.to_json())Publish a plan once, then replan around real operational changes without replacing the rest of the schedule:
from rosterspec import AssignmentPlan, AssignmentRef
published = AssignmentPlan.from_solve_result(problem, engine.solve(problem))
replanned = engine.replan(
changed_problem,
published,
locked_assignments=[
AssignmentRef(worker_id="blair", shift_id="evening", demand_id="support")
],
)
assert replanned.metrics.coverage_priority_proven
assert replanned.metrics.stability_priority_proven
print(replanned.impact.stability_cost.total)Hard constraints and locks come first, followed by target coverage, minimum symmetric assignment difference, and finally preferences and fairness. Slot indexes are presentation artifacts and do not participate in continuity or locking.
Representative diagnostic output:
{
"code": "DEMAND_NO_ELIGIBLE_WORKER_V1",
"message": "Demand night/senior has no eligible worker.",
"repair": {
"code": "ADJUST_QUALIFICATION_DEMAND_V1",
"verified": true,
"status_after": "OPTIMAL",
"coverage_delta": 2
}
}flowchart LR
A[AI generates scenario.json] --> B[Pydantic validation]
B --> C[rosterspec doctor]
C --> D[Stable diagnostics and rule codes]
D --> E[AI or developer edits configuration]
E --> F[Deterministic solve]
F --> G[Explanation and verified repairs]
An LLM is useful for producing and editing structured configuration. It is not a safe source of truth for constraint enforcement. RosterSpec uses CP-SAT and deterministic validation for the actual decision path.
flowchart TD
A[Problem JSON] --> B[Pydantic validation]
B --> C[Doctor and policy diagnostics]
C --> D[Explicit rule packs]
D --> E[OR-Tools CP-SAT model]
E --> F[Solver]
F --> G[Result interpreter]
G --> H[Validation report]
G --> I[Explanation report]
G --> J[Verified repair suggestions]
G --> K[Before / after comparison]
Hard constraints, such as required qualifications and minimum coverage, may never be violated by a returned assignment. Soft objectives express preferences and tradeoffs, such as target coverage, employee preferences, and workload fairness. The objective trace shows which scoring terms contributed to a choice without presenting those contributions as causal proof.
Target coverage has strict priority over the softer preference and fairness tradeoff. RosterSpec derives the smallest safe dominance weight from the bounded secondary objective, so changing a preference or fairness weight cannot silently reduce coverage. Solver metadata records the effective weight and whether maximum coverage was proven.
The CP-SAT model uses one decision variable per eligible worker and shift/demand pair. Coverage counts are aggregated while solving; stable slot indexes are materialized afterward for reports, validation, explanations, and repair comparisons.
LLMs can make scenario authoring faster. They can also invent qualifications, miss temporal edge cases, or propose a repair that causes a different violation. RosterSpec therefore treats AI output as untrusted input: validate it, return stable codes, solve deterministically, then apply and re-run every candidate repair before exposing it as verified.
- Omnichannel support week: ten agents, five days of overlapping coverage, multilingual and specialist queues, availability, hour limits, preferences, fairness, and a verified soft-target repair.
- Fulfillment peak week: twelve workers, three days of early/late operations, four specialist roles, availability, hour limits, preferences, fairness, and complete target coverage.
- Pediatric ward weekend pressure: ten nurses, day/night rotations, compound qualifications, individual rest rules, stable infeasibility diagnostics, and a verified adjustable-demand repair.
- Regional operations DST rotation: forty workers, forty overlapping shifts, 120 demand slots, explicit crew availability, compound qualifications, ISO-week limits, a daylight-saving fold, and a published-plan callout replan with hard locks and proven minimum disruption.
- Focused diagnostic fixtures: small support, warehouse, and hospital cases isolate exact preference, rest-conflict, candidate-trace, and repair behavior for tests.
See the example catalog for commands and expected outcomes. These are configurable operational policies, not legal or healthcare-compliance rules.
With canonical input ordering, one CP-SAT search worker, a fixed seed, and pinned RosterSpec and OR-Tools versions, the same supported runtime produces the same canonical assignments and objective. Run metadata records the input hash and solver version. Cross-version equivalence is not claimed, and formulation upgrades may select a different schedule among tied optima.
RosterSpec does not infer solver correctness from a few plausible schedules or a line-coverage number. Its release evidence uses independent and adversarial checks:
- Independent oracles: generated exhaustive enumeration verifies complete tiny schedules across hard and soft rules, while reference formulations check larger coverage, preference, and fairness outcomes without reusing the production objective implementation.
- Generated invariants: property tests exercise qualifications, minimum coverage, timezones, repair verification, and replanning stability across generated scenarios.
- Contract locks: generated schemas and golden fingerprints protect the public CLI, HTTP, and MCP JSON boundaries from accidental drift.
- Adversarial change detection: the weekly mutation gate enforces a ratcheted score and rejects any mutant that runs without tests.
- Scale evidence: fixed deterministic-time budgets enforce aggregated-model size, feasible-run, assignment-validity, and small-case optimality thresholds; weekly artifacts retain the complete branch, conflict, solve-rate, and model-size observations without wall-clock equality claims.
- Public-envelope proof: the exact 60-worker, 100-shift, 200-slot hosted boundary is solved and assignment-validated both directly and through an isolated API process; a separate load test executes distinct real solver processes concurrently.
- Product proof: browser tests run the production standalone playground at desktop and 320 px, cover failure recovery and high-risk confirmation, and reject serious or critical Axe findings.
- Release integrity: locked toolchains, a Python 3.11–3.13 matrix, exact wheel/sdist allowlists, a fresh-environment wheel smoke test, and provenance attestations protect the shipped artifact.
See CONTRIBUTING.md for the local commands and the public release checklist for the go/no-go contract.
RosterSpec is not a SaaS, payroll system, legal-compliance product, LLM scheduler, generic constraint solver, or enterprise workforce-management suite.
The first public alpha is release-candidate quality. See AGENTS.md for the machine-oriented contract, docs/architecture.md for design details, docs/threat-model.md for the trust boundaries, and docs/project-story.md for the extraction narrative. Public JSON evolution is defined by docs/compatibility.md; release history lives in CHANGELOG.md.
Apache-2.0.
