API server & client

The API server & client guide covers the resource model, the git-backed commit semantics, and the /x/ extension endpoints end to end.

longeron.server

Requires the server extra (pip install "longeron[server]"); the GitProjectStore itself needs only git on PATH.

Serve a workspace as an OMG Systems Modeling API server (git-backed).

longeron serve [path] (or serve() / create_app()) exposes a directory of .sysml files – or a single file – over the REST resource model of the OMG Systems Modeling API & Services specification, the same surface the pilot-implementation servers offer and clients like pymbe (and longeron.client) consume:

GET  /projects
GET  /projects/{projectId}
GET  /projects/{projectId}/commits
POST /projects/{projectId}/commits
GET  /projects/{projectId}/commits/{commitId}
GET  /projects/{projectId}/commits/{commitId}/elements      (paged)
GET  /projects/{projectId}/commits/{commitId}/elements/{elementId}
GET  /projects/{projectId}/commits/{commitId}/roots

Storage is git-backed and honest: the served path is the project, and an API commit is a git commit that touched the .sysml sources beneath it (listed via git log). Elements at a historic commit are parsed from git show <sha>:<path> blobs through the content-addressed model cache (longeron.workspace), so revisiting a ref is as fast as a warm load. The uncommitted working tree is always exposed as the head pseudo-commit working. Everything is read-only except POST .../commits, which accepts pilot-style identity/payload change records and materializes them: the changes are imported onto the working-tree model and the affected files are rewritten as .sysml text. The server never runs git commit – agents and tools must not auto-commit user repositories; review the diff and commit yourself, which is exactly the point of the git mapping.

Endpoints under /x/ are longeron extensions (no pilot server has them): POST /x/validate, POST /x/instantiate/{qname}, POST /x/simulate/{qname}, POST /x/interpret/{qname}, and GET /x/render/{qname}.svg wrap the validator, interpreter, and headless renderer.

Security: this is a local-first development server – no authentication, no TLS – and it binds to 127.0.0.1 by default. Do not expose it beyond a trusted network. Requires the server extra (FastAPI, uvicorn, pyecore); the one external tool is git on PATH (without it the workspace is still served, as a single working commit).

longeron.server.WORKING_COMMIT_ID = 'working'

the pseudo-commit id under which the uncommitted working tree is served

class longeron.server.GitProjectStore(path='.')[source]

Bases: object

One served workspace: project/commit/element views over a git repo.

Usable on its own (no FastAPI needed) – create_app() wraps it in HTTP routes. All git access is read-only (rev-parse, log, ls-tree, show); apply_commit() writes .sysml files to the working tree but never touches the git index or history.

git_commits()[source]

API commit records for the git commits that touched the served .sysml sources, oldest first. previousCommit chains within this filtered list (the project’s history, not the whole repo’s).

Return type:

list[dict[str, Any]]

commits()[source]

All commits, ending with the working pseudo-commit for the uncommitted working tree (equal to head content when clean).

Return type:

list[dict[str, Any]]

resolve_commit(commit_id)[source]

Normalize a commit id (working, a full sha, or any git rev the repo can resolve) or raise SysMLError.

Return type:

str

model_at(commit_id)[source]

The merged model at a commit; historic refs are parsed from git show blobs and memoized (refs are immutable), the working tree is loaded through longeron.load() and memoized behind a stat fingerprint of the served files (edits invalidate).

Return type:

Model

records_at(commit_id)[source]

Flat API records at a commit (memoized: per immutable ref, and for the working tree until its stat fingerprint changes – so a paginated listing projects the model once, not once per page).

Return type:

list[dict[str, Any]]

apply_commit(body)[source]

Materialize a POSTed commit into the working tree.

The body is a pilot-style commit ({"change": [{"identity": {"@id": ...}, "payload": {...}|null}, ...]}) or a bare list of such entries / flat records. Semantics per change entry, against the element ids of the working-tree model:

  • unknown id + payload – add: the new element records (with their membership records naming an owner, and any typing / specialization relationship records) are imported and attached;

  • known element id + payload – update: name, short name, flag, and body fields are patched onto the element;

  • known relationship-record id + payload – retarget: the owner’s typing/specialization entry is rewritten;

  • payload nulldelete the element (or relationship).

Only the .sysml files owning affected top-level elements are rewritten (regenerated with longeron.to_sysml(), which normalizes formatting); untouched files are never rewritten. The result is left uncommitted on purpose: tools must not auto-commit user repositories, so review git diff and commit yourself.

Return type:

dict[str, Any]

longeron.server.create_app(path='.')[source]

A FastAPI app serving path (requires longeron[server]).

Return type:

Any

longeron.server.serve(path='.', *, host='127.0.0.1', port=9000)[source]

Run the API server (blocking). longeron serve [path] --port N.

Binds to 127.0.0.1 by default: the server is local-first and does no authentication. Plain uvicorn.run – no signal-based reload tricks, so this works identically on Windows and POSIX.

Return type:

None

longeron.client

Requires the client extra (pip install "longeron[client]").

Typed client for OMG Systems Modeling API servers.

Client talks to any server exposing the pilot-implementation REST resource model (projects -> commits -> paginated elements) – including longeron serve (longeron.server) and the OMG pilot servers. It ports the good bones of pymbe’s APIClient (Link-header pagination, project/commit browsing, the POST identity/payload change form) without the traitlets/ipywidgets machinery:

from longeron.client import Client

with Client("http://localhost:9000") as client:
    project = client.list_projects()[0]["@id"]
    model = client.fetch_model(project)            # working tree
    old = client.fetch_model(project, commit=sha)  # any git commit

fetch_model rebuilds a longeron.model.Model from the flat API records via longeron.api.model_from_api_records() – the derived source/target endpoint arrays every pilot-style server serializes make the records navigable, so structure, ownership, typing, and specialization all come back. push_commit sends changes the other way.

Requires the client extra (httpx): pip install 'longeron[client]'. Pure Python; works identically on Windows and POSIX.

class longeron.client.Client(base_url='http://localhost:9000', *, page_size=2000, timeout=30.0, http=None)[source]

Bases: object

A synchronous Systems Modeling API client.

base_url names the server (default the pilot-conventional http://localhost:9000). Pass http to supply a pre-configured httpx.Client-compatible object instead – e.g. a Starlette TestClient wrapping an app in-process, which is how longeron’s own test suite exercises client and server together without a network.

list_elements(project, commit=None)[source]

All element records at a commit (default: the working tree / head), transparently following pagination.

Return type:

list[dict[str, Any]]

fetch_model(project, commit=None)[source]

Download and rebuild the model at a commit (default: working tree). See longeron.api.model_from_api_records() for the structural fidelity contract.

Return type:

Model

push_commit(project, changes, *, description='')[source]

POST a commit. changes is either a list of change entries (pilot {"identity": {"@id": ...}, "payload": {...}|null} form, or flat records, which are wrapped) or a whole Model, which is projected to API records first (that projection needs pyecore: longeron[ecore]).

Against longeron serve, the server materializes the commit by rewriting the affected .sysml files in its working tree – it never runs git commit (tools must not auto-commit user repos); the response’s written field lists the files to review.

Return type:

dict[str, Any]

validate(commit=None, *, strict_imports=False)[source]

POST /x/validate (longeron servers only).

strict_imports is forwarded to the server, mirroring longeron.validation.validate(): additionally warn for bare standard-library names that resolve only through the implicit library-visibility hop.

Return type:

dict[str, Any]

instantiate(qname, commit=None, **bindings)[source]

POST /x/instantiate/{qname} (longeron servers only).

Return type:

dict[str, Any]

simulate(qname, events=None, inputs=None, commit=None)[source]

POST /x/simulate/{qname} (longeron servers only).

Return type:

dict[str, Any]

interpret(qname, strategy='nominal', seed=None, commit=None, bindings=None, selection=None)[source]

POST /x/interpret/{qname} (longeron servers only): an M0 interpretation of the population under qname – the JSON shape of longeron.m0.Interpretation.to_dict().

Return type:

dict[str, Any]

render_svg(qname, commit=None)[source]

GET /x/render/{qname}.svg (longeron servers only).

Return type:

bytes