Reference
A practical map of the SolverForge workspace and the companion repos around it.
Crate & Runtime Map
Use this page when you need to decide which crate or companion repository should own a piece of work.
Default starting point
For most application code, depend on solverforge and stay on the facade until
you have a concrete reason to go lower-level.
This map is aligned with the published solverforge 0.19.9 crate and current
release workspace.
The facade re-exports the normal modeling, scoring, projection, configuration,
custom-search, and retained runtime surface, including
solverforge_constraints, Projection, ProjectionSink, SolverConfig,
PhaseConfig, MoveSelectorConfig, SearchContext, CustomSearchPhase,
ScalarGroup, ScalarAssignmentRule, ScalarGroupLimits,
SharedNodeDiagnostics, SharedNodeId, SharedNodeOperation, direct
cross-join .group_by(|left, right| key, collector), cross-join
.project(|left, right| row) projected scoring, row-aware chained cross joins
through Bi, Tri, Quad, Penta, and an arity-free Chain, direct cross-join grouped
complements, symmetric and directed projected self-joins, projected grouped
complements, score weight helpers such as fixed_weight and hard_weight,
collector helpers such as count, sum, load_balance, consecutive_runs,
collect_vec, and indexed_presence, plus advanced grouped-scalar assignment,
conflict-repair extension types, phase and move-label telemetry, bounded
applied-move and candidate-pull traces, candidate-trace provenance types, and
CVRP profile helpers such as domain = "cvrp", route_hooks,
savings_hooks, savings_metric_class, route_distance, route_feasible, and
savings_feasible. The grouped-scalar construction cursors, runtime model,
provider, and candidate-metric registries are solver-internal; applications
reach grouped construction through ScalarGroup::assignment(...),
group_name, and grouped_scalar_move_selector rather than by importing those
types. That keeps app code on solverforge unless it needs to implement
lower-level solver internals directly.
Workspace crates
| Crate | Owns | Reach for it when… |
|---|---|---|
solverforge |
the public facade and re-exports | you are building an app and want the normal public API |
solverforge-core |
score types, descriptors, domain traits, and dynamic capability contracts | you are extending lower-level abstractions or implementing core-facing helpers |
solverforge-macros |
#[planning_solution], #[planning_entity], #[problem_fact], #[solverforge_constraints] |
you need derive behavior, model glue, or constraint-function compilation |
solverforge-scoring |
constraint streams, typed relational operators and terminals, incremental scoring, and shared grouped node state | you are working directly on scoring internals or advanced scoring extensions |
solverforge-config |
TOML/YAML parsing, resolved selector policy, candidate-trace config, acceptors, and builders | you need direct config construction or parsing outside the stock solve path |
solverforge-solver |
runtime compiler, phases, cursor selectors, retained lifecycle, and telemetry | you are building custom runtime behavior beyond facade-level use |
solverforge-bridge |
dynamic binding contracts, logical IDs, scores, explicit slot capabilities, and the compiled runner | you are implementing or maintaining a binding layer |
solverforge-console |
tracing-driven console output | you want the standard terminal UX or progress formatting |
solverforge-cvrp |
CVRP-specific helpers and distance utilities | your problem is route-centric and the domain benefits from these helpers |
Relational scoring internals
Fluent cross joins and same-collection unique combinations now score through
constraint::relational::OperatorTerminal. Cross joins nest JoinNodes;
same-collection combinations use SelfJoinNode with an identity-preserving
filter. The old cross_bi_incremental, cross_tri_incremental, and per-arity
self-join incremental constraint modules are no longer the implementation.
Named cross Bi/Tri/Quad/Penta streams adapt the common tree. Cross
Penta::join returns stream::chain::Chain; subsequent Chain::join calls
extend it without a fixed arity ceiling. Each chained condition compiles
independently, receives the whole prior borrowed row, and can use a key domain
different from earlier relationships. Chain filters and weights receive the
typed row rather than a new positional closure signature for every arity.
Low-level stream::relational::operator types compose collection, filter,
merge, project, group, join, self-join, existence, flatten, and complement
producers. Derived payloads belong to evaluation or retained-state owners;
borrowed views and generational row identities preserve lineage without
retaining solution references. Group and membership changes can replace rows
during either retraction or insertion, so consumers process both removed and
inserted rows in RowChanges.
This is not a claim that every fluent family has migrated. Specialized unary, grouped, projected, existence, and flattened constraint families still exist. Likewise, reusable grouped-node sharing remains distinct from automatic compiler-owned sharing of arbitrary derived consumers. Check the tagged scoring implementation when extending internals; the repository’s architecture notes retain some intermediate-stage descriptions.
Companion repositories
| Repo | Owns | Use it when… |
|---|---|---|
solverforge-cli |
scaffolding and code generation | you are starting a new app or extending a generated shell |
solverforge-py |
the tagged v0.6.10 Python source line, compiled-model PyO3 binding, retained diagnostics, native row-domain enforcement, and embedded UI asset bridge |
you want Python model authoring backed by the Rust solver engine |
solverforge-ui |
retained-job frontend controls and scheduling-facing components | you need a web UI around a retained solve lifecycle |
solverforge-maps |
road networks, routing, matrices, and map-backed planning helpers | you need route costs, geometry, or spatial planning support |
Practical dependency rules
- Start with
solverforge-clito scaffold the app shell. - Start with the PyPI
solverforgepackage when the application surface is Python and you do not need a generated Rust web/API/CLI shell. PyPI publishessolverforge 0.6.10; use the matchingsolverforge-py v0.6.10tag for source and example development on SolverForge 0.19.7. - Keep application code on the
solverforgefacade unless a lower-level crate unlocks something you actually need. - Keep scalar/list model declarations in the
planning_model!manifest and variable attributes; solver config consumes declared hooks rather than inferring nearby or construction-order behavior. - Use scalar variables for direct assignments and list variables for ordered membership; SolverForge 0.19 has no separate chained-scalar sequence model.
- Keep reusable grouped constraint work inside a
#[solverforge_constraints]function; do not add app-level caches or public sharing helpers. - Add
solverforge-uionly if the product needs retained-job UI flows. - Add
solverforge-mapsonly if routing or map-backed costs are part of the planning model. - Use
solverforge-pyfor Python classes, decorators, explicit scalar/list metadata, callbacks, candidate metrics, retained jobs and diagnostics, and embedded UI assets over the native Rust engine. - Reach into
solverforge-solverdirectly only when configuration and the public facade stop being enough. - Reach into
solverforge-scoringmodule-scoped names such asstream::projected::DirectedBiorconstraint::projected::DirectedBionly when you are extending scoring internals; application constraints should use the fluentjoin(equal_bi(...))surface.
Typical stacks
| Scenario | Typical stack |
|---|---|
| service or CLI planner | solverforge-cli scaffold + solverforge |
| Python-authored planner | PyPI solverforge package or the solverforge-py v0.6.10 source tag |
| web app with retained lifecycle UI | solverforge-cli + solverforge + solverforge-ui |
| routing or fleet optimization | solverforge-cli + solverforge + solverforge-maps |
| research or advanced runtime work | solverforge plus selected lower-level crates |
What not to do
- Do not start on the lowest-level crates unless the public API is clearly insufficient.
- Do not push app-specific business rules into SolverForge crates just because the extension point exists.
- Do not treat
solverforge-uiorsolverforge-mapsas part of this repository’s workspace; they are companion repos with their own release lines.See also
- SolverForge docs
- SolverForge Python docs
- Integration Boundaries
- Modeling Cheat Sheet