A non-sandboxed macOS app that hosts a local HTTP server exposing the SwiftStan commands over an OpenAPI interface. It is the execution tier in the SwiftStan ecosystem: it owns cmdstan and the ~/Documents/StanCases filesystem, and clients (notably SwiftStanApp) talk to it over HTTP.
SwiftStanServer is part of a three-project ecosystem coupled only by HTTP contracts:
| Project | Role |
|---|---|
| SwiftStanLibrary | The distributable Swift library wrapping cmdstan and file-translation utilities |
| SwiftStanServer (this) | macOS app linking SwiftStanLibrary and serving its commands over HTTP |
| SwiftStanApp | GUI client; no build dependency on this project — talks over HTTP only |
The HTTP layer is generated by Apple's Swift OpenAPI Generator with a Hummingbird transport.
- macOS 26+
- Xcode 26+ with Swift 6
- cmdstan installed locally
The repo includes the .xcodeproj with all source files, the OpenAPI spec, entitlements, and SPM dependencies already wired.
- Clone this repo and open
SwiftStanServer.xcodeprojin Xcode. - Trust the build plugin when prompted (OpenAPIGenerator). The first build generates
APIProtocol/Typesfromopenapi.yaml. - Set your cmdstan path in the GUI or via the
$CMDSTANenvironment variable. - Build and run.
| Setting | Source (in priority order) |
|---|---|
| cmdstan path | GUI / UserDefaults → $CMDSTAN env var → hardcoded default |
| Port | GUI / UserDefaults serverPort → default 8080 |
| StanCases root | $STAN_CASES env var → ~/Documents/StanCases |
The server binds to 127.0.0.1 only. Change the port or cmdstan path in the GUI, then restart the server.
The canonical spec is SwiftStanServer/openapi.yaml (SwiftStanApp keeps a byte-identical copy). All operations are POST /v1/<command> and return HTTP 200 with a CommandResult:
{ "status": "...", "error": "", "outputPath": "/path/to/output" }A non-empty error field signals a logical failure. Real 4xx/5xx are reserved for transport faults.
| Method | Path | Description |
|---|---|---|
GET |
/v1/health |
Liveness check; returns resolved cmdstan and StanCases paths |
These shell out to cmdstan and can take minutes. The server keeps the HTTP connection open until the command returns.
| Endpoint | Request Schema | Extra Fields |
|---|---|---|
POST /v1/compile |
CompileRequest |
install, force |
POST /v1/sample |
SampleRequest |
install, nosummary |
POST /v1/optimize |
CmdstanRequest |
— |
POST /v1/pathfinder |
CmdstanRequest |
— |
POST /v1/laplace |
CmdstanRequest |
— |
POST /v1/generated_quantities |
CmdstanRequest |
— |
POST /v1/stansummary |
CmdstanRequest |
— |
POST /v1/ulam |
UlamRequest |
force |
All cmdstan requests share these common fields:
{ "model": "bernoulli", "arguments": ["key=value"], "cmdstan": "/path/override", "verbose": false }These run entirely in-process and return quickly.
| Endpoint | Description | Extra Fields |
|---|---|---|
POST /v1/csv2json |
Convert CmdStan CSV output to JSON | — |
POST /v1/alist2dsl |
Convert R-style alist to DSL format | — |
POST /v1/stancode |
Generate Stan code from DSL | — |
POST /v1/stan2alist |
Convert Stan code back to alist | force |
POST /v1/runinfo |
Extract run metadata from results | — |
File-translation requests use { "model": "bernoulli", "verbose": false }.
# Liveness check
curl http://127.0.0.1:8080/v1/health
# Generate Stan code for bernoulli model
curl -X POST http://127.0.0.1:8080/v1/stancode \
-H 'Content-Type: application/json' \
-d '{"model":"bernoulli"}'
# Compile the model
curl -X POST http://127.0.0.1:8080/v1/compile \
-H 'Content-Type: application/json' \
-d '{"model":"bernoulli"}'
# Run MCMC sampling
curl -X POST http://127.0.0.1:8080/v1/sample \
-H 'Content-Type: application/json' \
-d '{"model":"bernoulli"}'Expected sample output: {"status":"...","error":""} with bernoulli.samples.csv appearing under ~/Documents/StanCases/bernoulli/Results/.
StanAPIHandler.swift—struct StanAPIHandler: APIProtocol; one method per operation forwarding to the matchingSwiftStanlibrary function. Synchronous blocking calls are wrapped inTask.detachedviaoffload(_:)so the event loop isn't starved during long-running cmdstan operations.ServerController.swift—@Observable @MainActorclass owning the HummingbirdApplicationlifecycle (start()/stop()).ServerSettings.swift— Resolves cmdstan path, port, and StanCases root from UserDefaults, environment, and defaults.SwiftStanServerApp.swift—@mainApp entry point; starts the server on appear.ContentView.swift— Minimal status GUI: running indicator, port, cmdstan path, Start/Stop button.
See SwiftStanLibrary for licensing terms.