src/main.rs defines the CLI entrypoint and Clap command tree. Command implementations live in src/commands/; larger generators use submodules such as src/commands/generate_constraint/ and src/commands/generate_domain/. Shared support code sits in src/app_spec.rs, src/countable_range.rs, src/error.rs, src/list_variable_metadata.rs, src/managed_block.rs, src/model_contract.rs, src/model_id.rs, src/output.rs, src/rc.rs, src/scaffold_target.rs, src/scalar_variable_hooks.rs, src/solver_config.rs, and src/template.rs. Integration tests live in tests/; their reusable generated-app harness lives in tests/support/, browser scenarios live in tests/e2e/, and scaffold/template assets live in templates/. The portable agent skill lives in skills/ and is installed by scripts/install-skill; csemver.toml configures csemver for releases.
solverforge-cli is the default entry point for new SolverForge applications. Treat the CLI as its own versioned product, distinct from the runtime crates and UI assets that generated projects target.
Current scaffold policy:
- current CLI package version is
3.6.0 - minimum supported Rust version is
1.95, matching the current SolverForge runtime crates - generated projects currently target
solverforge 0.22.0; the default web shell additionally targetssolverforge-ui 0.9.0andsolverforge-maps 2.1.4; the MCP shell additionally targetsrmcp 3.5.1 solverforge new <name>is the only public scaffold path and produces a neutral app shell--shell web|api|cli|mcpis the current public shell selector;webis the default,apiomits frontend assets,cliomits Axum/SSE routes and frontend assets, andmcpdelivers the solver as an MCP server over stdio and stateless Streamable HTTP- API/CLI/MCP app specs omit
ui_source, and subsequent CLI mutations must preserve that absence - the MCP shell keeps the shared core (
domain/,constraints/,solver/,data/, DTOs) and addssrc/mcp/;solveis task-backed with retainedjobIdmetadata for task-capable clients, tasks have no TTL and remain for the server process lifetime, failed/cancelled solves map to corresponding MCP task states, stdio is the default transport, concrete--hostIPs preserve rmcp Host validation but the HTTP transport is unauthenticated with a single shared solver/task store so a non-loopback bind is a documented trusted-network-only limitation, and the runtimeconsolefeature stays off so the banner never corrupts the stdio channel solverforge connectprints MCP client configuration and writes in-project config for the harness target (--write opencode|claude|cursor|vscode; each merges instead of clobbering)- Tauri scaffolding is deferred; do not document or implement a public Tauri shell unless that work is explicitly reopened
- users shape the app afterward through facts, entities, solution/score metadata, variables, constraints, and generated data
- generated docs and CLI version output must distinguish CLI version from scaffold runtime/UI target
scalarandlistare the only planning variable kinds accepted by the public CLI and app-spec projection- scalar variables accept either a fact-collection range or a validated non-negative half-open countable range and expose current candidate/nearby/construction hook metadata; list variables expose current domain, distance, route/savings, ownership, construction-order, precedence, and solution-trait metadata
- ordered sequences and routes use list variables; do not model sequence topology as a scalar predecessor field
standardis a demo size label only; do not reintroduce it as a variable kind or scaffold familytemplates/scalar/genericis the embedded neutral scaffold used bysolverforge new;templates/list/genericis not a publicnewselector- generated
Cargo.tomlfiles must carryrust-version = "1.95"plus the current explicit dependency baselines for the selected shell from the template/materialization code - the repository ships portable agent skills at
skills/solverforge-modeling/andskills/solverforge-ui/with an agent-centric installer atscripts/install-skill; keep their documented shell set, scaffold targets, and command surface aligned with the live CLI
When changing templates or scaffold behavior, follow the current repo reality over older starter-template assumptions. Do not add legacy aliases, compatibility shims, migration fallbacks, or automatic rewrites for unmanaged pre-refactor file shapes unless that is explicitly requested.
cargo build: compile thesolverforgebinary.cargo run -- --help: run the CLI locally and inspect commands.cargo test: run Rust unit tests, scaffold contract tests, and generated-app runtime pipeline tests.cargo test --test runtime_pipeline_test -- --nocapture --test-threads=1: run the phase-marked runtime pipeline suite directly.cargo test --test runtime_mcp_pipeline_test -- --nocapture --test-threads=1: run the MCP-shell runtime pipeline suite directly.make test-runtime: run only the generated-app runtime pipeline tests.make install-e2e: install Playwright Chromium locally.make test-e2e: run Playwright browser tests against ephemeral generated apps.make test-full: run binary/unit tests, installer and skill-integrity tests, scaffold contract tests, runtime pipeline tests, and Playwright tests in order.make test-support: run only the installer behavior and skill reference-integrity tests.cargo fmt --all: apply Rust formatting.cargo clippy --all-targets -- -D warnings: enforce lint-clean code.pre-commit run --all-files: run the repository hooks, including YAML checks,gitleaks,fmt, andclippy../scripts/install-skill --agent <harness>(ormake install-skill ARGS='--agent <harness>'): install the bundled agent skills into the selected harness's own skills directory.
Use standard Rust style with 4-space indentation and rustfmt output as the source of truth. Prefer snake_case for modules, files, functions, and test names; use PascalCase for types and enums. Keep CLI flags, generated file names, and module names descriptive and consistent with existing commands such as generate_constraint and sf_config.
Add narrow unit tests close to the code in sibling test files or #[cfg(test)] child modules when validating parsing, rewriting, or template helpers. Put end-to-end CLI behavior in tests/, following existing names like *_test.rs and test_* functions. When changing scaffolding or generated code, cover both file creation and key output content assertions.
Prefer a small number of readable, high-signal end-to-end phases over a large number of narrow tests. The main generated-app suites are:
tests/scaffold_test.rs: scaffold contract and generatedcargo checktests/runtime_pipeline_test.rs: phase-marked generated-app runtime pipelinestests/runtime_mcp_pipeline_test.rs: phase-marked MCP-shell pipelines driven by the realrmcpclienttests/e2e/*.spec.js: Playwright browser pipelines against ephemeral generated apps
Both runtime and browser suites must:
- scaffold fresh temp apps through the real CLI
- mutate them through the real CLI
- boot generated servers on random ports
- preserve failure artifacts under
target/test-artifacts/ - keep phase boundaries explicit in code and logs
Current end-to-end scenario policy:
- neutral shell is covered as a bootable empty app
- mixed is covered as a seeded generated solve in both runtime and browser scenarios, with required scalar assignment and complete list placement
- the scalar-only scenario covers the full pause/resume/cancel/delete lifecycle
- the scalar-only runtime scenario covers full compact telemetry, bounded candidate detail, and qualified trace provenance
- the MCP scenario models a mixed scalar-plus-list problem, generates the sample data, and drives both stdio and stateless Streamable HTTP through the real
rmcpclient: annotated tool surface, task-backed solve to a terminal snapshot with scalar assignment and complete list placement, retained lifecycle via a legacy client, and byte-level stdio stdout purity during a solve
SolverForge 0.22.0 uses list variables as the sequence and route model. The
generated-app runtime and browser scenarios must continue to start and observe
a real mixed scalar/list solve.
For scaffold changes, prefer assertions that check the generated contract directly:
- dependency wiring for the selected shell:
solverforgeeverywhere,solverforge-uiandsolverforge-mapsonly for web-shell projects,rmcponly for the mcp shell, and the optionalschemars/schemafeature enabled only for the mcp shell - CLI version vs runtime target messaging
- generated README version/runtime source disclosure
- typed solver SSE payload shape and typed frontend hooks
- full compact SolverTelemetry projection plus the separate retained candidate-trace diagnostics route and qualified-run entry point
solverforge generate dataownership boundaries:src/data/mod.rsis the stable wrapper andsrc/data/data_seed.rsis compiler-owned generated sample data- managed block ownership boundaries:
domain exports, solution collections, entity variables, constraint modules, and constraint calls require their
@solverforge:begin .../@solverforge:end ...markers solverforge.app.tomlprojection: facts, entities, scalar/list variable metadata, constraints, demo sizes, solution/score metadata, runtime target metadata, and web-shellstatic/generated/ui-model.json- scaffolded
cargo checkmust preserve generated registry declarations; before a coordinated target is published, sibling-checkout validation must be explicit viaSF_USE_LOCAL_PATCHES=1, which writes a temporary.cargo/config.tomlpatch file without rewriting generatedCargo.toml; repeat the registry-only gate after publication
Follow the commit style already used in history: fix: ..., refactor: ..., style: ..., chore: .... Keep commits scoped to one behavior change. PRs should explain user-visible CLI impact, list verification commands run, and link the relevant issue. Include concrete examples when flags, generated files, or template output change.
Releases are cut with csemver, configured by the checked-in csemver.toml.
Never hand-edit CHANGELOG.md or a version surface the config owns
(Cargo.toml, Cargo.lock, package.json, package-lock.json) or the
prose version lines in README.md, AGENTS.md, WIREFRAME.md, and
skills/solverforge-modeling/SKILL.md. Run csemver --release-as vX.Y.Z
(or let conventional commits pick the bump) instead of bumping by hand; the
tool owns the release commit, the tag, and the changelog.
Do not commit generated projects, secrets, or credentials. The pre-commit config runs gitleaks; keep it enabled. When tests or generated scaffolds touch published SolverForge crate versions, verify Cargo.toml template changes and corresponding integration tests together.
skills/solverforge-modeling/ is a portable Agent Skill (SKILL.md plus
references/ and scripts/) that teaches an agent to model planning problems
with this CLI. Keep it aligned with the live CLI surface:
SKILL.mdfrontmattername/descriptiondrive discovery; keep the shell set, scaffold targets, and command surface documented in the body current.scripts/install-skillcopies the skill into each selected harness's own skills directory (opencode, Claude Code, the cross-harness Agent Skills standard), at user or project scope. It never symlinks or shares a location, and it writes a.solverforge-skillmarker into each installed copy so--listand--uninstallnever touch an entry it did not install.skills/solverforge-modeling/scripts/solve-smoke-test.shverifies a generated app per shell (MCP covers transport health only; protocol proof lives inruntime_mcp_pipeline_test); update it when a shell's runtime surface changes.make install-skill ARGS='--agent <harness>'wraps the installer.
Keep SKILL.md harness-agnostic; do not encode assumptions about one client.
Generated apps should behave like production references, not toy demos.
Keep these rules aligned across the single neutral scaffold and all generated domain shapes that users create afterward:
- backend services track best solution separately from live status telemetry
- compact status/snapshot/SSE telemetry projects every current SolverTelemetry aggregate and phase/selector/move/applied-move breakdown
- bounded candidate pulls are retained separately and exposed only through
/jobs/{id}/telemetry; do not copy them into ordinary lifecycle traffic - qualified candidate-trace jobs use additive
/jobs/qualifiedinput with all five externally attested SHA-256 digests and a non-empty producer - status endpoints return
currentScore,bestScore, solver status, and latest snapshot revision - SSE payloads carry typed lifecycle metadata including
eventType,eventSequence,lifecycleState, andsnapshotRevision - retained lifecycle events include
progress,best_solution,pause_requested,paused,resumed,completed,cancelled, andfailed - frontends use lifecycle-aware hooks including
onProgress(meta),onSolution(snapshot, meta),onPaused(snapshot, meta),onResumed(meta),onCancelled(snapshot, meta),onComplete(snapshot, meta), andonFailure(message, meta, snapshot, analysis) - snapshot-bound analysis and retained
/jobs/{id}/snapshotflows stay aligned with the shared UI backend contract - reconnect bootstrap is derived from
SolverManagerstatus plus the latest retained snapshot revision; do not cache or replay last SSE text locally - Pause resumes from the runtime-retained checkpoint, Stop maps to
/jobs/{id}/cancel, and Delete is terminal cleanup only - progress-only events update status, not the rendered board
- generated demo data flows expose
/demo-dataas the catalog and/demo-data/{id}for selected data; frontends derive the default ID from the catalog and must not hard-code/demo-data/STANDARD - generated web-shell UI composition should use shipped
solverforge-uiprimitives before adding template-owned JavaScript src/data/data_seed.rsand web-shellstatic/generated/ui-model.jsonare compiler-owned; user-facing seams are thesolverforge generate datacommand, stablesrc/data/mod.rswrapper, and web-shellstatic/sf-config.json- generated domain and constraint mutation is canonical-only: current managed block shapes are required, not inferred from old layouts
Do not reintroduce:
- raw top-level score-only progress payloads
- starter-specific solve/render lifecycles
- docs that blur CLI version with runtime/UI target
standardas a planning variable kind- scalar predecessor topology; ordered sequences belong to list variables
- hidden scaffold/template aliases
- shell selectors beyond the canonical
web,api,cli, andmcp - Tauri or other shell aliases before a real scaffold implementation exists
- fallback migration code for legacy generated files
Test harness notes:
- ephemeral generated apps should be the default validation path; do not rely on manually scaffolded directories for routine testing
- runtime/browser failures should leave actionable logs and artifacts under
target/test-artifacts/ - phase output should remain human-readable and ordered, even when tests grow