solverforge-cli 2.2.3

CLI for scaffolding and managing SolverForge constraint solver projects
solverforge-cli-2.2.3 is not a library.

solverforge-cli

Default entry point for new SolverForge projects.

Use this CLI to scaffold, grow, and validate SolverForge applications. The CLI is its own versioned product: solverforge --version reports the CLI package version and the scaffold dependency targets separately.

Current CLI package version: 2.2.3.

Required Rust version: 1.95 or later.

New projects currently target these crate versions:

  • solverforge 0.19.3
  • solverforge-ui 0.7.0 for the default web shell
  • solverforge-maps 2.1.4 for the default web shell
cargo install solverforge-cli
solverforge new my-scheduler

Current Contract

Public scaffold path:

  • solverforge new <name>

That command creates a neutral app shell. The default shell is web; use --shell api for an HTTP API without frontend assets or --shell cli for a Clap command-line app without Axum. Users shape the app afterward through facts, entities, solution/score metadata, variables, constraints, generated data, and solverforge.app.toml. Shell choice is recorded as [app].shell; it is not a modeling family selector. The current public shell set is exactly web, api, and cli; a Tauri shell is intentionally deferred and is not generated by this release line.

Planning variable kinds are canonical:

  • scalar for single-value assignment variables backed by either --range <facts> or a half-open --countable-range <from..to>
  • list for sequence variables backed by --elements <facts>

Countable ranges are validated as non-negative usize values with from < to, are projected into solverforge.app.toml and the web UI model, and render as numeric value lanes in the generated frontend:

solverforge generate variable hour --entity Shift --kind scalar --countable-range 0..24

Scalar variables can also carry opt-in SolverForge hook metadata for model-owned candidate selection, nearby candidate selection, distance meters, and construction ordering:

solverforge generate variable resource_idx --entity Task --kind scalar --range resources \
  --candidate-values resource_candidates \
  --nearby-value-candidates nearby_resources \
  --nearby-entity-candidates nearby_tasks \
  --nearby-value-distance-meter resource_distance \
  --nearby-entity-distance-meter task_distance \
  --construction-entity-order-key task_priority \
  --construction-value-order-key resource_priority

Those flags only write #[planning_variable(...)] metadata and project it into solverforge.app.toml. Web-shell projects also project that metadata into static/generated/ui-model.json; users still own the Rust hook functions.

Ordered sequences and routes use list variables. List variables expose the full current SolverForge list metadata surface. Use the stock CVRP profile when the solution implements the runtime's CVRP contract:

solverforge generate variable visit_order --entity Route --kind list --elements visits --domain cvrp

For custom list domains, use --distance-meter, --intra-distance-meter, --route-hooks, --savings-hooks, --savings-metric-class-fn, --element-owner-fn, --construction-element-order-key, --precedence-duration-fn, --precedence-successors-fn, and --solution-trait. These values are preserved in solverforge.app.toml and the web UI projection. They name user-owned Rust implementations. The stock CVRP profile already owns its meters, route/savings hooks, metric class, and solution trait, so those entries cannot be overridden alongside --domain cvrp.

Scalar groups and conflict repairs are opt-in modeling resources. They are identified only by exact IDs: scalar-group names and snake_case constraint IDs. Unless --skip-solver-config is passed, solverforge generate scalar-group writes both grouped construction and grouped local-search solver.toml refs for assignment-backed and candidate-backed groups. solverforge check validates those refs across the solver config graph, including construction phases, top-level selectors, neighborhoods, nested selector children, and partition child phases. The CLI writes those generated refs inside one # @solverforge:begin solver-config / # @solverforge:end solver-config region with exact-ID owner comments for each generated phase; generated apps still consume plain solver.toml through the umbrella solverforge crate.

standard is only a demo dataset size label in solverforge.app.toml; it is not a variable kind.

Basic domain flow:

solverforge new my-scheduler
cd my-scheduler
solverforge generate fact resource --field category:String --field load:i32
solverforge generate entity task --field label:String --field priority:i32
solverforge generate variable resource_idx --entity Task --kind scalar --range resources --allows-unassigned
solverforge generate data --size large
solverforge server

Shell variants:

solverforge new batch-scheduler --shell cli
solverforge new service-scheduler --shell api

Generated projects use managed block markers as the canonical CLI edit points. Domain exports, solution collections, entity variables, constraint modules, and constraint calls must retain their @solverforge:begin ... / @solverforge:end ... regions for later generate and destroy commands. Project-local .solverforge/templates/entity.rs.tmpl and .solverforge/templates/solution.rs.tmpl overrides are supported only when they emit those same canonical managed blocks.

solverforge generate data owns the generated data pipeline. It keeps src/data/mod.rs as the stable import wrapper, rewrites src/data/data_seed.rs with deterministic sample builders, and persists dataset size defaults in solverforge.app.toml. sample is the default mode; stub is available for shape-only data. The supported demo size labels are small, standard, and large. Generated values are structurally useful rather than domain-specific fake business data.

The default web-shell frontend is intentionally thin. It composes shipped solverforge-ui 0.7.0 primitives such as SF.createBackend(...), SF.createSolver(...), and SF.rail.createTimeline(...) instead of vendoring app-specific UI frameworks. Domain-specific examples belong in quickstarts, not in the built-in scaffold catalog. API-shell and CLI-shell projects do not generate static/, static/generated/ui-model.json, or ui_source; later domain mutations keep that shell boundary intact.

Command Surface

Core commands:

  • solverforge new <name> creates the neutral scaffold. --shell web|api|cli selects the generated app shell; web is the default. --skip-git skips the initial Git repository/commit, and --skip-readme skips the generated project README.
  • solverforge generate fact|entity|variable|constraint|solution|score|data mutates the current project through the canonical generated surfaces.
  • solverforge generate scalar-group|conflict-repair wires opt-in model resources by exact ID.
  • solverforge destroy fact|entity|variable|constraint|solution|scalar-group|conflict-repair removes generated resources and rewrites the app spec/UI projection.
  • solverforge check, solverforge info, and solverforge routes inspect the generated project. routes applies only to web/API shells.
  • solverforge config show|set reads and writes non-phase solver.toml settings. Ordered phases edits are manual. Generated model-resource refs in that file are exact-ID graph references, not aliases; destroy re-renders the CLI-managed solver config region and blocks when nested or user-authored solver config still references the resource.
  • solverforge config set candidate_trace.max_entries <N> enables the bounded candidate-pull diagnostics and rejects zero/non-integer capacities.
  • solverforge server runs web/API generated apps through Cargo. CLI-shell projects run directly with cargo run -- demo-data.
  • solverforge test delegates to cargo test.
  • solverforge completions <shell> emits shell completions.

Generated project manifests include rust-version = "1.95" and dependencies for the selected shell. The web shell includes the current direct web/runtime support dependencies:

  • axum 0.8.9
  • tokio 1.52.3
  • tokio-stream 0.1.18
  • tower-http 0.6.11
  • tower 0.5.3
  • serde 1.0.228
  • serde_json 1.0.150
  • uuid 1.23.5
  • parking_lot 0.12.5

The API shell keeps solverforge, Axum, Tokio, SSE, tower-http CORS, serialization, and parking_lot, but excludes solverforge-ui, solverforge-maps, and static file serving. The CLI shell keeps solverforge, Clap, Tokio, serialization, and parking_lot, but excludes Axum, tower-http, tokio-stream, solverforge-ui, solverforge-maps, and static/.

Persistent .solverforgerc files are loaded from the project root first and then from ~/.solverforgerc. Recognized preferences are intentionally narrow: port, no_color, and quiet.

Generated Runtime Diagnostics

Generated web/API apps expose every compact SolverTelemetry aggregate, including applied/not-doable/rejected moves, hard-score direction counts, conflict-repair counters, construction counters, current phase detail, per-selector and per-move breakdowns, and the bounded applied-move trace. These fields are carried consistently by status, snapshot, and typed SSE payloads.

Candidate-pull traces are intentionally not copied into those ordinary control-plane payloads. After enabling [candidate_trace], fetch the retained diagnostic publication from GET /jobs/{id}/telemetry. The response includes the full bounded pull prefix, canonical identities and dispositions, digests, resolved phase plan, execution policy, input provenance, and qualification status paired with the exact retained job status.

POST /jobs/qualified starts the same retained lifecycle with externally attested SHA-256 schema, instance, initial-state, core-tree, and loaded-build digests. Existing clients continue to use POST /jobs; the qualified route is an additive diagnostic entry point. Tracing remains opt-in because candidate pull detail can be large.

Validation Flow

End-to-end validation is split into explicit phases so the real production pipeline stays readable:

  • cargo test Rust unit tests, scaffold contract tests, and generated-app runtime pipeline tests
  • make test-runtime phase-marked runtime pipeline against ephemeral generated apps only
  • make test-e2e Playwright browser tests against ephemeral generated apps only
  • make install-e2e install Playwright Chromium locally before the first browser run
  • make test-full full pipeline: binary/unit tests, scaffold contract tests, runtime pipeline, then Playwright

The runtime and browser suites both scaffold fresh temp apps, mutate them through the real CLI, boot the generated servers on random ports, and clean up automatically. Failure artifacts are written under target/test-artifacts/. By default, end-to-end validation preserves the generated registry dependency declarations and applies no local patches. During a coordinated runtime prerelease whose target is not yet on crates.io, set SF_USE_LOCAL_PATCHES=1; the harness writes a temporary .cargo/config.toml with explicit [patch.crates-io] entries only for dependencies present in the generated manifest. Generated manifests are not rewritten. Repeat the registry-only gate after the target is published.

Current scenario coverage:

  • neutral shell: scaffold, boot, and verify the empty production shell
  • mixed app: scaffold mixed shape, seed non-empty mixed demo data, start a real retained solve, verify required scalar assignment and complete list placement, then cancel and delete the job through the generated runtime/browser surface
  • scalar-only app: seed non-empty data and run it through the real generated solver, including typed SSE, status, analysis, checkpointed Pause/Resume, user-facing Stop as runtime cancel, terminal-only Delete, and status/snapshot reconnect bootstrap; the runtime pipeline also verifies full aggregate telemetry, bounded candidate detail, and qualified trace provenance SolverForge 0.19.3 supports mixed scalar/list construction, canonical mixed local-search defaults, and list-based sequence modeling. The CLI suite proves the mixed path in both runtime and browser pipelines; the scalar-only scenario keeps the deeper pause/resume, analysis, reconnect, and qualified-trace checks.

For solver and domain extension guidance after scaffolding, see the runtime docs in solverforge: Extend the solver and Extend the domain.

License

Licensed under the Apache License, Version 2.0. See LICENSE.