Files
solvecraft/docs/book/src/dev/commands.md
yhamil04 c0a0da225a Ribbon tooltips: help for the Solid > Modify tools, and new toolbar commands must have it (#2758) (#7134)
* Ribbon tooltips: help for the Solid > Modify tools; new toolbar commands need it (#2758)

Writes the two-sentence help for the 16 Modify tools that had none (en, fr,
ja, zh), and adds a test that fails when a toolbar command has no help; the
190 older ones are on a backlog that only shrinks. AGENTS.md, CONTRIBUTING.md
and the Adding a command guide say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Ribbon tooltips: the help test reads the ribbon as the toolbar lays it out (#2758)

Review: commands placed by a workspace section without .at(...) were not
checked; 79 of them join the backlog. Physical Material's help no longer
promises the centre of mass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Ribbon tooltips: French help uses the glossary terms (#2758)

Matériau, Apparence and Scinder, as rlartot asked in review; Delete Face
says the hole stays open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Ribbon tooltips: the help rule fits the commands skill's size limit (#2758)

AGENTS.md became a router to skills on main, so the rule lives in
skills/solidcraft-commands/SKILL.md, kept under its 3600-character limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Ribbon tooltips: Arabic, Hebrew and Vietnamese help; the backlog follows main (#2758)

Arabic, Hebrew and Vietnamese are complete catalogs now, so the 16 texts
come in those too. Twelve toolbar commands that landed before the rule
join the backlog; the Render commands, which left the ribbon, leave it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 22:30:15 +00:00

3.9 KiB

The command engine

Every user-visible action is a command: a CommandSpec registered in crates/engine/src/cmd/, with a dotted, lower-case id (solid.extrude, sketch.create, timeline.rollback). The toolbar, dialogs, marking menu, S box, scripts, the CLI, the control channel and MCP all run commands through Session::execute(id, params). Commands take JSON parameters and never open dialogs; a dialog is a front-end form that builds the parameters.

CommandSpec::new("solid.fillet", "Fillet", fillet)
    .at("SOLID", "MODIFY")      // toolbar tab and panel ("" = not on the toolbar)
    .icon("fillet")             // drawn in code, assets/icons/ui/source/icons.rs
    .key("F")                   // default shortcut
    .params("edges: [[x,y,z] | {body, index}]; radius: expr; …"),

run is fn(&mut Session, &Value) -> Result<Value>, and enabled is fn(&Session) -> Result<(), String>; the error string is the disabled-button tooltip. The params string is the one-line documentation shown by solidcraft-cli commands, MCP's list_commands and the command reference.

A command that changes the design is undoable by default: the session snapshots the document before it runs, and a failing command leaves the document unchanged. Feature commands add a feature to the timeline and let the document evaluate it; they validate their inputs first (units, ranges, references) and return BadParams instead of building a broken feature.

Only the registry's own dotted ids name commands (matched ignoring case); any other id fails with unknown command, which names up to three close ids: a typo's (solid.extrud), or one ending in the same word (file.open: did you mean doc.open?).

Adding a command

  1. Add a CommandSpec to the right file in crates/engine/src/cmd/ and implement run.
  2. Give it input and output schemas: a parameters type (its contract) and a reply type in the module for its command file under crates/engine/src/schema/ (schema/features.rs for cmd/features.rs, and so on; create it for the file's first contract), built from the shared field types in schema/types.rs. Register them with checked!(…), .contract(…) and .output(…), as solid.extrude does, and add the command to that module's schemas_and_the_key_check_agree test, with error-message cases and a reply test. The parameters type documents each parameter (keep the .params(…) prose too, for now), and describe_command serves both schemas to agents and scripts. A test (every_command_has_input_and_output_schemas) warns for a command without them, and will fail it once the rule becomes required; the commands that predate the rule are listed in schema/unconverted.txt, which only shrinks. Command schemas walks through it, with the shared types and a checklist.
  3. Write engine tests that measure the result: volume, area, and face/edge/vertex counts against values you can derive by hand.
  4. The hostile-input test (hostile_params_never_panic in crates/engine/src/tests.rs) runs your command automatically with every documented parameter set to junk. It must return errors, never panic.
  5. For UI work, add a scenario (see Test harnesses).
  6. A command the ribbon shows (through .at(…) or a section in crates/ui-egui/src/workspace.rs) ships with its help tooltip: two short sentences, what the tool does and then when to use it, in your own words. Add the message help.<id> to a new file in assets/locales/pending/ (English, every catalog in COMPLETE in crates/ui-egui/src/i18n.rs, which a test requires, and any other language you can write) and the id to DOCUMENTED in crates/ui-egui/src/command_help.rs. The test every_toolbar_command_has_help_or_is_on_the_backlog fails for a ribbon command without help; the older ones on its BACKLOG only shrink (#2758).