A deploy control plane for the sglang and vllm charts. Design and rationale:
docs/swiss-design.md.
One document, read by both binaries. Found via --config, $SWISS_CONFIG,
./swiss.yaml, ~/.config/swiss/swiss.yaml.
catalog: https://modelsphere.github.io/model-catalog/ # the default when left out
cluster:
name: prod
profile:
file: ./examples/site-prod.yaml # or configMap: swiss/site-profile
server:
addr: ":8080"
allowDeploy: falseThe CLI works without one (--catalog / --profile, the catalog defaulting to
https://modelsphere.github.io/model-catalog/); swissd requires one.
go build -o swiss ./cmd/swiss
swiss catalog list
swiss catalog show kimi-k2.5
swiss plan --model qwen3.6-35b-a3b --release fallback-qwen-01 \
--service-id fallback-qwen-01 --explain
swiss plan --model qwen3.6-35b-a3b --release fallback-qwen-01 -o plan.json
swiss render --plan plan.json # helm template; values.schema.json runs here
swiss diff --plan plan.json # exit 2 when something would change
swiss apply --plan plan.json # release must exist
swiss install --plan plan.json # release must not exist--explain shows which layer set each value. emit is not implemented.
cd web && npm install && npm run build && cd ..
go build -o swissd ./cmd/swissd
./swissd --config examples/swiss.yamlPOST /api/login /api/logout GET /api/session (open)
GET /api/cluster /api/sites /api/catalog /api/catalog/{model}
GET /api/releases /api/nodes /api/deployments /api/runs
PUT /api/profile
POST /api/plans /api/diff /api/apply /api/install (allowDeploy only)
applyWith on the site profile chooses the backend for a new install: helm (the default when the field is omitted) or llmsvc when the LLMService CRD is served. A release already in the cluster stays on the backend that owns it. llmsvc requires the plan's source.schema to be v2; empty means v1 and is rejected with 400 and nothing is written. Helm accepts v1 and v2. The CLI swiss install and swiss apply stay on helm. See docs/swiss-design.md.
CI publishes the image to ghcr.io/modelsphere/swissd and
4pdosc/swissd on Docker Hub, and the chart to
oci://ghcr.io/modelsphere/charts/swiss, at one version. The OCI chart pulls the
GHCR image; charts in the modelsphere helm repo
are the other channel and pull from Docker Hub.
helm install swiss oci://ghcr.io/modelsphere/charts/swiss -n swiss --create-namespace \
--set 'rbac.namespaces={models,kimi}'From a checkout:
docker build -t ghcr.io/modelsphere/swissd:$(./hack/bump.sh) .
helm install swiss ./helm/swiss -n swiss --create-namespace \
--set 'rbac.namespaces={models,kimi}'rbac.namespaces is rendered into both the Roles and cluster.namespaces, so
swissd lists only namespaces it was granted — a Role cannot authorise a
cluster-wide list. rbac.scope: cluster drops the list and reads everything.
rbac.applyWith is helm (today's grant), both (that grant plus
LLMService), or llmsvc (LLMService writes and the read grants, without Secret,
Role or workload writes). Anything else is refused. The new-install backend is
applyWith on the site profile, which an operator edits without a helm upgrade.
Deploy mode needs a volume and one replica: the database holds the audit log and the rollback history, neither of which is cluster state. Upgrades do not depend on it -- the whole plan is written beside every release, and swissd falls back to reading it from there.
One instance per cluster, inside the cluster it manages. Read the RBAC section of
the design doc before installing: rbac.scope decides whether swissd can read
every Secret in the cluster.