How sysml-rs works
sysml-rs implementationstatus: pre-alpha
This page gives you the mental model of sysml-rs before you read any code: what the pipeline is, which abstractions everything else hangs off, and where each subsystem’s deep documentation lives. The companion code map tells you which crate and file to open.
The deep, canonical material is the developer guide in the repository — twelve numbered guides covering each subsystem in detail. This page orients; the guides explain.
The pipeline
Section titled “The pipeline”Text goes in and a queryable, executable model comes out:
.sysml / .kerml source │ ▼ tree-sitter CST sysml-parser-incremental (the sole parser) │ lowering (ast_builder) ▼ ModelGraph sysml-core — the ONE intermediate representation │ ▼ name resolution + sysml-core resolution & validation tiers, validation cached incrementally by sysml-ide-db (salsa) │ ▼ consumers execution (sysml-runtime) · queries (sysml-query) · diagrams (sysml-diagram) · every transportTwo facts carry most of the architecture:
ModelGraphis the universal IR. Defined incrates/lang/sysml-core/src/graph.rs, it is what the parser produces and what the runtime, query engine, diagram generators, and all four transports read. Nothing bypasses it and nothing talks sideways: parser → core → consumers.- One service hub fronts everything.
SysmlService(crates/tooling/sysml-service/src/lib.rs) owns the model state and the runtime sessions; CLI, LSP, REST, and MCP are thin transports that dispatch named commands into it. The same operation behaves identically no matter how you reach it.
Parsing: tree-sitter, and only tree-sitter
Section titled “Parsing: tree-sitter, and only tree-sitter”sysml-parser-incremental wraps a generated tree-sitter grammar
(crates/lang/sysml-parser-incremental/tree-sitter/grammar.js) whose keyword,
operator, and enum tables are derived from the OMG Xtext grammars by
generate_from_xtext.sh. The parser is incremental and error-tolerant:
unsupported syntax surfaces as a parse diagnostic rather than silently doing
something else. The CST is lowered into a ModelGraph by the ast_builder
modules.
There is no second parser. An earlier Pest-based batch parser was deleted; any document that mentions it is stale.
Grammar changes are expensive: regenerating parser.c (ABI 14, pinned — ABI 15
compiles and then segfaults) takes tens of minutes. tools/ts-grammar/ exists
to make that iteration loop bearable.
Deep guide: 02-parsing.md
The semantic graph and the spec-is-gospel posture
Section titled “The semantic graph and the spec-is-gospel posture”sysml-core holds the semantic model: Element, Relationship, and
ModelGraph, plus resolution, validation, elaboration, and canonical JSON.
Its type system is not hand-written — crates/lang/sysml-core/build.rs runs
the sysml-codegen generators over the fetched OMG spec sources (TTL
vocabularies, shapes, XMI, Xtext) to emit the ElementKind enum, typed
property accessors, and validation dispatchers. That is why a fresh clone must
run tools/fetch-references/fetch.sh before cargo build, and why
.generated.rs files are never hand-edited.
This is the project’s core posture: the specification is the authority. Where implementation and spec disagree, the implementation is wrong; language behaviour changes need a spec citation, not an argument from taste. The twin rule is fail hard rather than degrade quietly — an unresolved name or unsupported construct produces a precise diagnostic, never a plausible fallback. Both rules are spelled out in CONTRIBUTING.md.
Name resolution runs over the whole workspace plus the standard library;
validation is tiered (structural, property/shape-derived, semantic), and every
diagnostic carries a stable code from the registry in
crates/lang/sysml-core/src/error_codes.rs — the same codes documented in the
diagnostics reference.
Deep guides: 03-resolution.md · 04-codegen.md · 05-validation.md
The service hub: one command registry, four transports
Section titled “The service hub: one command registry, four transports”Every user-visible operation is a method on SysmlService annotated with
#[service_command] (a proc macro from sysml-service-macros). The macro
generates the typed request, the metadata, and a link-time registration, so
the registry assembles itself — there is no hand-maintained command list.
Dispatch is one function: execute_command in
crates/tooling/sysml-service/src/command_trait.rs looks a command up by name
and invokes it against the shared service.
The four transports are deliberately thin:
- CLI (
sysml-cli) — see CLI workflows and the command reference. - LSP (
sysml-lsp-server) — see the language server and editors. - REST/WebSocket (
sysml-api, axum, loopback-only by default) — see the service API. - MCP (
sysml-mcp, one tool per command) — see the MCP server.
None of them reimplements logic, so behaviour cannot drift between surfaces —
and the test suite enforces it with cross-transport parity fixtures. The
machine-readable catalogue of every registered command is served at
GET /commands by sysml-api and rendered in the
API and MCP catalogue.
Deep guides: 11-sysml-service-design.md · 10-mcp-server-architecture.md · 07-lsp-architecture.md
Incrementality: the salsa analysis host
Section titled “Incrementality: the salsa analysis host”sysml-ide-db wraps analysis in a salsa
incremental-computation database, following the rust-analyzer pattern:
AnalysisHost (crates/tooling/sysml-ide-db/src/host.rs) owns the mutable
database; it hands out immutable Analysis snapshots that can be queried
concurrently. SysmlService holds the host and locks it only briefly — to set
inputs after an edit or to take a snapshot.
What this buys: after a keystroke, tree-sitter reparses only the edited region, and salsa recomputes only the queries whose inputs actually changed. Parse results, resolution, elaboration, diagnostics, and cached ViewModels are all salsa queries, so an unchanged file costs nothing on re-analysis. It is the reason one in-process model can serve an interactive editor session and batch CLI runs with the same code path.
The runtime: execution, verification, physics
Section titled “The runtime: execution, verification, physics”sysml-runtime lowers an elaborated ModelGraph into its own execution IR
(src/compiler/) and executes it:
- Discrete behaviour — state machines, actions, message/flow exchange
(
src/actions/,src/flows/). - Expressions, constraints, and cases — expression evaluation, constraint
checking to verdicts, calculation/analysis/verification cases
(
src/expressions/,src/constraints.rs,src/cases/). - Continuous dynamics — ODE/DAE integration via the
diffsolsolver, and hybrid discrete-plus-continuous stepping (src/hybrid.rs), plus Monte Carlo and sweep tooling on top.
This is honestly the youngest part of the codebase. The models under
examples/ are what the regression suite locks down; novel model shapes will
find gaps, and interfaces here move fastest. The user-facing view of the same
machinery is on executing models and
the Simulation App.
Deep guide: 06-execution.md
Diagrams: ViewModel is the wire contract
Section titled “Diagrams: ViewModel is the wire contract”Diagrams are server-rendered, never parsed or laid out from scratch in the browser:
ModelGraph → ViewRequest → DiagramIR → ViewModel → React-SVG renderer / exportssysml-diagram turns a view request (a standard view family plus expansion,
filter, and frame inputs) into DiagramIR — semantic nodes, ports, edges,
compartments — and joins it with design tokens, text map, and interaction map
into a ViewModel (crates/lang/sysml-diagram/src/view_model.rs).
ViewModel is the only diagram wire contract: the Simulation App’s
React-SVG canvas renders it, the CLI exports it, and simulation, verdict, and
diagnostic overlays attach to it as sidecars keyed by element id rather than
mutating the scene. PlantUML export runs off the same graph.
User-facing view: views and diagrams. Deep guide: 09-vis-pipeline-architecture.md
Layering rules that matter to contributors
Section titled “Layering rules that matter to contributors”The workspace is two crate groups plus a test tier, and dependencies only point downward:
crates/lang/implements the SysML v2 specification itself — the semantic model, parser, runtime, diagram exporters, manifests. Spec-defined behaviour, not tooling convenience. Lang crates never depend on tooling crates.crates/tooling/builds the usable surfaces on top — service hub, salsa analysis, resolution of project dependencies, storage, and the four transports.crates/testing/is a leaf: it depends on everything and nothing depends on it.
Within each group there are numbered layers (foundations → core → parser →
features → service → transports); a lower layer never imports a higher one, so
the build resolves in one pass and you can test sysml-core without starting
a server. Before adding a crate, a dependency, or a cross-layer edge, read
00-architecture.md
— it is the rulebook, including where recently deleted crates went.
Where to go next
Section titled “Where to go next”- Where the code lives — the crate-by-crate map, with entry points and “where would I change X?” answers.
- Developer guide index — all twelve deep guides.
- CONTRIBUTING.md — environment setup, generated-file rules, and what a reviewable PR looks like.