API server & client¶
longeron serve exposes any workspace as an OMG Systems Modeling API &
Services server, and
longeron.client.Client consumes any server speaking that resource model
(longeron’s own, or the OMG pilot implementation). Together they close the
interchange loop: fetch a model from a server at any point in its history,
work with it as a regular longeron Model, and push changes back.
pip install "longeron[server]" # fastapi, uvicorn, pyecore
longeron serve path/to/models --port 9000
from longeron.client import Client # pip install "longeron[client]"
client = Client("http://localhost:9000")
project = client.list_projects()[0]
commits = client.list_commits(project) # oldest -> newest, then "working"
model = client.fetch_model(project) # the working tree, as a Model
old = client.fetch_model(project, commit=commits[0]["@id"])
Resource model¶
Endpoint |
Returns |
|---|---|
|
the served workspace as a single project |
|
one project record |
|
commit records, oldest first, ending with |
|
materialize change records into the working tree |
|
one commit record |
|
flat API-JSON records (paged via |
|
one element record |
|
the root namespace element(s) |
Element records are the same API JSON that
longeron export --format api produces, including the derived
source/target endpoint arrays that pilot-ecosystem consumers (pymbe)
use to recognize and navigate relationships. Pagination follows the pilot
convention (?page[size]=N, a Link header carrying the next URL), so
existing pilot clients paginate unchanged.
Git-backed commits, honestly¶
The server does not invent a commit store — the workspace’s git repository is the store:
project — the served directory (or single
.sysmlfile). The project@idis a deterministic UUID of its path; the name carries a pilot-style timestamp suffix that pilot clients parse.commit — a git commit that touched the served
.sysmlsources (git log, oldest first;@idis the full git SHA, and any rev-parseable ref works in URLs).previousCommitchains within this filtered history.elements at a commit — the model parsed from
git show <sha>:<path>blobs at that ref, through the same content-addressed cache the loader uses, so revisiting historic refs is fast after the first parse.working— the uncommitted working tree, always the last commit in the list. This is the head everything defaults to. Its projection is memoized behind a stat fingerprint of the served files (paths, sizes, mtimes), so repeated requests — every page of a listing, element fetches — reuse one parse until a file changes on disk.
POST /projects/{id}/commits accepts pilot-style change records
({"identity": {"@id": ...}, "payload": {...} | null}; the pymbe
write-side format) and materializes them: new elements are imported
into the working-tree model and attached where their membership records
say, updates patch names/flags, null payloads delete, and only the
.sysml files owning affected top-level elements are rewritten (formats
are normalized by the exporter; untouched files are never rewritten). The
response’s written field lists the files.
The server deliberately never runs git commit: agents and tools must
not auto-commit user repositories. Review the diff and commit yourself —
that human checkpoint is the point of mapping the API onto git. Renames
pushed through the API do not rewrite textual references elsewhere in the
model; POST /x/validate afterwards will flag any reference you broke.
Fidelity contract: API records carry structure — kinds, names, flags, ownership, typing, specialization — but not expression trees, so pushed new content cannot carry attribute values. Updates and deletes patch the parsed working-tree model in place, so everything already in your files (values, calc bodies) survives a push that touches the same file.
Extension endpoints (/x/)¶
No pilot server executes models; these are longeron extensions, thin
wrappers over the validator, interpreter, and renderer, namespaced under
/x/ so the spec surface above stays exactly what pilot clients expect:
Endpoint |
Wraps |
Body (JSON, all fields optional) |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
— |
Client mirrors them as validate(), instantiate(), simulate(),
interpret(), and render_svg() — validate(strict_imports=True)
forwards the body flag. Interpretation responses are the JSON
shape of Interpretation.to_dict() (an M0 population with stable
qname#index identities); equal seeds reproduce equal populations across
requests. Rendering additionally needs the diagram stack (ipyelk +
node); a server without it answers 501.
Security¶
Local-first by design: no authentication, no TLS, and the default bind is
127.0.0.1. Anyone who can reach the port can read the models and write
to the working tree. Do not expose the server beyond a trusted network;
put it behind an authenticating reverse proxy if you must share it.
Platform notes¶
Server and client are pure Python — FastAPI, uvicorn, and httpx are all
Windows-clean, and file I/O is explicit UTF-8 throughout. The one external
requirement is git on PATH; without it the workspace still serves,
with working as the only commit. Git tree paths in refspecs are composed
with forward slashes on every OS.
Interoperability¶
The server was cross-checked against pymbe (the pilot-ecosystem Python
client): its APIClient lists the project, selects commits, and downloads
elements into a navigable pymbe Model unchanged. The reverse direction —
Client against a pilot server — uses only spec resources plus the
pilot’s pagination convention.