Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ or CAN and radio injection, raises `simantic.NotSupported` and names the gap
instead of quietly doing nothing. You can follow what each engine covers in
[simantic-core#183](https://github.com/simantic-dev/simantic-core/issues/183).

This `backend=` dispatch is meant to be the one place engine choice happens —
see [`docs/unified-surface.md`](docs/unified-surface.md) for where the CLI and
MCP install are expected to grow the same logic.

## Testing with pytest

Take the `sim` fixture and write ordinary tests:
Expand Down
3 changes: 3 additions & 0 deletions docs/session-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,6 @@ an agent that needs a loop, is better served by code: the loop runs in the
engine's process, only the conclusion enters the transcript, and the script
becomes a fixture. `Sim` is that path; the MCP servers remain for interactive
poking and are expected to shrink to a thin adapter over it.

See [`unified-surface.md`](unified-surface.md) for where the CLI dispatch and
an eventual unified MCP server's client-side install are expected to land.
48 changes: 48 additions & 0 deletions docs/unified-surface.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Where the unified surface lands

This package (`pip install simantic`) is already the front door for the
engines: it locates and installs the Renode and Rust binaries, and `Sim`
dispatches between them by `backend=`. Two extensions of that same role are
planned but not yet built. Recording them here so the direction is written
down before the code is.

## The `Sim` dispatch API grows into the CLI's job too

`Sim(backend="renode"|"rust")` already picks an engine per call from Python.
Today nothing on the command line does the equivalent — `simantic`/`smtc`
only wraps `auth`/`install`/`status`, and running a simulation from a shell
means invoking the engine's own binary directly (`sim ...`) with no backend
choice at that layer.

The plan is for `simantic`/`smtc` to grow the same dispatch `Sim` already has,
instead of engines each keeping a separate CLI surface. Concretely: the
`backend=` selection and the `NotSupported`-with-a-named-gap behavior that
`Sim` already implements become the one place that decision is made, called
from both the Python API and the command line, rather than duplicated if a
CLI grows its own copy.

## The MCP install front door

Two MCP servers exist today, one per engine, and neither is reachable from
this package: `pyrite-mcp` (Rust engine, active) and the Renode engine's MCP
server (stale). The two engines have genuinely different capabilities — e.g.
Renode's `gdb_*` control plane and multi-machine/CAN/radio scenarios don't
exist on the Rust side — so unifying them isn't one server absorbing the
other's tools; it's a `Sim(backend=...)`-shaped front door that dispatches
each call to whichever engine implements it. Per
[`session-api.md`](session-api.md#why-not-mcp), the MCP servers are expected
to shrink into thin adapters over `Sim` as that dispatch layer takes shape.

This package is the natural client-side install point for whichever unified
MCP server results, for the same reason it already installs the engines
instead of asking a user to find them: `install.py` already has the
"locate this pinned binary, fetch it if missing, verify it against a
checksum" logic (`install_engine`, `install_rust_engine`). An MCP server
binary is one more thing of that shape — `simantic install mcp` mirrors
`simantic install engine`, and `simantic mcp` launches what it resolved, the
same relationship `Sim` has to the simulation binaries today.

This package still would not *implement* the MCP server — that stays where
the engine code lives — it would only be the thing a user runs `pip install`
for and then finds the server through, the same boundary that already holds
for the simulation engines.