Skip to content

Flexo Change Adapter

The Flexo Change Adapter connects a Flexo branch to a CI system. It is a small, self-hosted service that polls one Layer 1 branch, records every head it observes in a durable journal, and hands each change to the CI runner you configure — GitHub Actions, GitLab or Jenkins — with the validation bound to the exact revision it saw, even if the branch has moved on by the time the job runs.

  • Repository: Open-MBEE/flexo-change-adapter (TypeScript, Node.js 24)
  • Status: initial alpha; the configuration, CLI and state format may change before 1.0

What it does

Responsibility How
Observe Polls the branch at /orgs/{org}/repos/{repo}/branches/{branch}; the first read is a baseline, every later head a branch change
Retain Commits each event, the actions it queued and the checkpoint together in SQLite, so a restart loses nothing and a queued action keeps its original destination
Pin Resolves a change to a Layer 1 lock on the observed commit and reads the model graph through it, checking the commit and ETag before and after, so the validated graph is the one that was observed
Validate Runs the selected checkers on that pinned revision and keeps the inputs, reports and results as evidence
Publish Optionally writes a JSON activity feed of the newest events for other applications to read

The pieces are independent: a feed-only configuration observes and publishes without any CI, a generic trigger starts a pipeline with the revision's metadata and nothing else, and a validation action carries the model itself to the runner.

Checkers and runners

An action pairs a task with a target. Each is a registered implementation chosen in configuration; there are no configurable commands or plugins to load.

Task Checks Runs on
engine-validation with engine: opensysml Syntax and semantics of the SysML v2 text with OpenSysML GitHub, GitLab, Jenkins
engine-validation with engine: sysml-toolkit The same, with the SysML Toolkit GitHub, GitLab, Jenkins
shacl-validation The RDF model graph against a project-chosen SHACL rule GitHub, GitLab, Jenkins
ci-trigger Nothing itself: starts a pipeline or job with the revision and event metadata GitLab, Jenkins

The text engines read a bundle of .sysml and .kerml files that the model's producer publishes as artifacts in the same Flexo repository and binds, by digest, into the RDF graph of the revision; the adapter verifies every digest before the engine runs. Each reviewed engine profile pins the engine version and standard library it executes. Passing a check says the selected engine accepted the pinned revision; it is not a claim of complete standards conformance.

On GitHub the runner is a private execution repository carrying the same reviewed worker source: inputs are retained there as Git objects and the workflow receives their identities, never a Flexo credential. On GitLab and Jenkins, validation runs on dedicated self-hosted workers that share a durable directory with the adapter; generic triggers need only an API token.

Configuration

One versioned JSON file selects the source, where state and the feed live, and the actions:

{
  "schema_version": 1,
  "id": "satellite",
  "state_directory": "./satellite",
  "source": {
    "type": "flexo",
    "endpoint": "https://flexo.example",
    "organization": "research",
    "repository": "satellite",
    "branch": "main"
  },
  "observation": { "mode": "poll", "interval_seconds": 30 },
  "feed": { "type": "json-feed", "path": "./satellite/output/activity.json" },
  "actions": [
    {
      "id": "opensysml",
      "on": ["branch-change"],
      "task": { "type": "engine-validation", "engine": "opensysml", "profile": "syntax-semantic-v1" },
      "target": { "type": "github", "owner": "research", "repository": "satellite-checks" }
    }
  ]
}

on selects branch-change, baseline or both. Paths resolve relative to the file. Credentials never appear in it: the adapter reads a Flexo bearer token from FLEXO_TOKEN (or FLEXO_USERNAME and FLEXO_PASSWORD, exchanged at the Auth service) and the CI tokens from the environment variables the target names. The repository's examples/configuration/ holds a starting point for each runner.

Running it

git clone https://github.com/Open-MBEE/flexo-change-adapter.git
cd flexo-change-adapter
npm ci

npm run adapter -- check  --config adapter.json          # validate offline, no credentials
npm run adapter -- run    --config adapter.json --once   # one poll and delivery round
npm run adapter -- status --config adapter.json          # inspect retained state
npm run adapter -- run    --config adapter.json          # keep polling

check is offline and creates no state. A compose.configured.yaml runs the same commands in a container with the configuration mounted read-only and /data as the persistent volume. The adapter is a source release rather than an npm package, and the repository's just recipes bring up a local Jenkins for trying the triggers without a hosted account.

Limits

Polling samples the branch head, so commits made between two polls are not seen individually; one process watches one branch. Verified validation is only as trustworthy as the worker: the watcher and the worker must run the same reviewed source and locked dependencies, which together form the validator identity retained with every result. The repository's status page records what has been verified on which platform.