møbius ("möbius") is a small Go CLI for GitOps repositories that manage Kubernetes clusters with ArgoCD.
Its job is to render the effective Helm-based cluster configuration for:
- the merge-base with the target branch
- the current merge request state
Then it compares both rendered results chart by chart and resource by resource, so reviewers can see what the merge request would actually change in the cluster.
The name comes from StarCraft: the Moebius Foundation was a formerly legitimate research group focused on archaeology. It explored sites created by a race older than the protoss, including Research Site KL-2.
Install the CLI locally with Go:
go install github.com/sohooo/moebius/cmd/mobius@latestInstall a pinned version:
go install github.com/sohooo/moebius/cmd/mobius@v0.1.0This requires a local Go toolchain. For GitLab CI, the container image remains the recommended distribution path.
Print the installed build metadata:
mobius versionmøbius is designed to run as a separate tool in a GitLab merge request pipeline, typically from the cluster configuration repository. A common production setup is to build and publish the møbius image once, then run that image on a Kubernetes GitLab runner.
In CI, møbius is meant to answer one question for reviewers:
What effective cluster change will this merge request produce?
møbius renders the cluster configuration at the merge-base and at the MR commit, compares both results, and turns that into a readable report.
For CI usage there are two main modes:
møbius diffPrints the report to the job output and optionally writes artifacts.møbius commentPosts the report back to the merge request as a sticky bot note.
Sample outputs:
- Markdown report: docs/sample-report.md
- GitLab MR note: docs/sample-comment.md
When a GitLab MR pipeline runs møbius comment, it:
- detects the current merge request from the GitLab CI environment
- resolves the merge-base against the configured base ref
- renders the effective cluster state at the merge-base and at the MR commit
- compares both rendered states chart by chart and resource by resource
- builds a GitLab-native markdown report
- finds the existing
møbiusMR note, if one already exists - creates that note if it does not exist yet
- updates the same note on later pipeline runs instead of creating duplicates
- leaves the note unchanged if the rendered report body is already up to date
The posted note contains:
- a top-level review summary with total counts
- a severity breakdown across changed resources
- validation error and warning counts
- an unvalidated count when no matching schema bundle is available for some resources
- short highlights for the highest-severity findings
- a per-cluster summary table
- one collapsible section per chart
- compact chart summaries with counts, kinds, severity summaries, and notable changes
- resource-level diff sections inside each chart section
- semantic diff snippets that highlight the effective Kubernetes changes
- per-resource severity labels with short human-readable findings
- validation findings when a rendered resource is structurally invalid, schema-invalid, or semantically suspicious
If there are no effective changes, møbius comment updates the sticky note to a short no-change message instead of deleting it.
Using møbius comment in the MR pipeline makes the rendered diff part of the merge request discussion itself.
That gives reviewers:
- a stable, visible diff directly on the MR instead of only in job logs
- a report they can quote, reference, and discuss in review threads
- an updated view on every pipeline run without accumulating multiple bot comments
- a more compact MR note for larger diffs, with chart details expanded only when needed
- a clearer picture of the effective cluster change than raw values-file edits alone
For very large reports, møbius can automatically fall back to a compact summary note and point reviewers to the pipeline artifacts for the full details.
The job environment should:
- fetch enough git history for merge-base calculation
- make the target branch ref, usually
master, available locally - provide the repository checkout
- provide
CI_PROJECT_ID,CI_MERGE_REQUEST_IID, andCI_JOB_TOKEN - provide either
CI_API_V4_URLorCI_SERVER_URL - provide network and credentials only if OCI chart access requires them
The repository in which the pipeline runs should include the cluster definitions and any referenced local charts. Layout configuration can come from built-in defaults, an optional repo-root config.yaml, or the MOBIUS_CONFIG_YAML environment variable.
For repositories that already use the default layout, the pipeline only needs to reference the møbius image. No explicit layout config is required.
Default-layout example:
mobius-diff:
stage: test
image: ghcr.io/sohooo/moebius:v0.1.0
tags:
- k8s
script:
- møbius comment --output-dir .mobius-out
artifacts:
when: always
paths:
- .mobius-out/This job uses the built-in defaults:
- clusters under
clusters/<cluster> - apps file
apps.yaml - release fields
name,namespace,project,chart,version - overrides at
overrides/{project}/{name}.yaml - fallback overrides at
overrides/{name}.yaml
Custom-layout example with configuration supplied entirely through CI:
mobius-diff:
stage: test
image: ghcr.io/sohooo/moebius:v0.1.0
tags:
- k8s
variables:
MOBIUS_CONFIG_YAML: |
layout:
clusters_dir: environments
apps:
file: releases.yaml
fields:
name: release_name
namespace: target_namespace
project: argocd_project
chart: chart_ref
version: chart_version
overrides:
path: values/{project}/{name}.yaml
fallback_path: values/{name}.yaml
script:
- møbius comment --output-dir .mobius-out
artifacts:
when: always
paths:
- .mobius-out/Configuration precedence is:
- built-in defaults
- optional repo-root
config.yaml - optional
MOBIUS_CONFIG_YAML - targeted CLI overrides such as
--clusters-dir
If you prefer to keep the diff only in job output, use møbius diff. If you want the report directly on the merge request, use møbius comment.
A sample markdown report is available in docs/sample-report.md.
A sample GitLab MR comment with collapsible chart sections is available in docs/sample-comment.md.
møbius can render markdown output for copy and paste, or post the same style of report directly into a GitLab merge request as a sticky bot comment.
For each selected cluster, møbius:
- loads layout configuration from built-in defaults, optional config.yaml, optional
MOBIUS_CONFIG_YAML, and targeted CLI overrides - resolves the merge-base with the configured base ref
- loads the configured apps file for each cluster
- renders each release with the Helm Go SDK
- applies override values from the configured override path
- splits the rendered output into individual Kubernetes resources
- compares baseline and current resources semantically and as raw text
- validates current rendered resources offline using structural checks, embedded schemas, rendered CRD schemas, and semantic validators
- renders the result as terminal output, markdown, or a GitLab MR note
flowchart TD
A["Load config.yaml"] --> B["Select clusters"]
B --> C["Resolve merge-base"]
C --> D["Build baseline workspace"]
C --> E["Use current worktree"]
D --> F["Load apps file"]
E --> F
F --> G["Render Helm releases"]
G --> H["Split into resources"]
H --> I["Compare baseline vs current"]
I --> J["Terminal diff"]
I --> K["Markdown report"]
I --> L["GitLab MR comment"]
Artifacts are written per chart and per resource:
current/<cluster>/<chart>/rendered.yamlcurrent/<cluster>/<chart>/resources/<kind>--<namespace-or-cluster>--<name>.yamlbaseline/<cluster>/<chart>/resources/<kind>--<namespace-or-cluster>--<name>.yamldiff/<cluster>/<chart>/<resource-key>.diffdiff/<cluster>/<chart>/<resource-key>.semantic.txt
The baseline is the git merge-base between HEAD and the configured base ref, not the current tip of the target branch.
Validation is offline-first:
- built-in Kubernetes resources use embedded schema bundles
- supported platform CRDs can use embedded schema bundles
- if a matching
CustomResourceDefinitionis rendered in the current chart, its schema takes precedence - semantic validators add warnings for suspicious-but-schema-valid configurations
- reports distinguish schema-validated resources from unvalidated resources and show whether validation used a rendered CRD or an embedded schema bundle
Build the binary:
make buildShow the local build metadata:
./bin/møbius versionInstall the published CLI directly with Go:
go install github.com/sohooo/moebius/cmd/mobius@latestRun the standard verification pass:
make verifyRender the diff for one cluster:
./bin/møbius diff --cluster kube-bravoRender markdown output that is ready to paste into a merge request:
./bin/møbius diff --cluster kube-bravo --output-format markdownPost or update the sticky merge request comment from a GitLab MR pipeline:
./bin/møbius commentDisable validation for debugging:
./bin/møbius diff --cluster kube-bravo --validate=falsePersist rendered artifacts and diffs:
./bin/møbius diff --cluster kube-bravo --output-dir .mobius-outBuild the container image:
docker build -t mobius:local --build-arg MOBIUS_VERSION=latest .Pin the container image to a specific published CLI version:
docker build -t mobius:v0.1.0 --build-arg MOBIUS_VERSION=v0.1.0 .By default, cluster definitions live under clusters/.
clusters/<cluster>/apps.yamllists the Helm releases for that cluster- each release entry can include fields such as
name,namespace,project,chart, andversion clusters/<cluster>/overrides/<project>/<chart>.yamlis the default primary override pathclusters/<cluster>/overrides/<chart>.yamlis the default fallback override path
Example:
clusters/kube-bravo/apps.yamlclusters/kube-bravo/overrides/test/hello-world.yaml
The demo repository also contains a sample chart under charts/hello-world.
møbius supports an optional repo-root config.yaml.
It uses the same schema as MOBIUS_CONFIG_YAML and can define:
- the cluster root directory
- the apps file name inside each cluster
- the field names used inside each release entry
- which canonical fields are required
- the primary and fallback override path patterns
The apps file is expected to be a top-level YAML list of release objects. møbius does not support nested release extraction, arbitrary YAML queries, or custom templating rules in layout config.
Layout precedence is:
- built-in defaults
- optional repo-root
config.yaml - optional
MOBIUS_CONFIG_YAML - targeted CLI overrides such as
--clusters-dir
Example field remapping:
layout:
apps:
fields:
name: release_name
namespace: target_namespace
project: argocd_project
chart: chart_ref
version: chart_versionconfig.yaml works well for repo-owned local conventions. MOBIUS_CONFIG_YAML works well for decoupled containerized CI usage. --clusters-dir remains available as an explicit override for layout.clusters_dir.
| Flag | Meaning | Default / Notes |
|---|---|---|
--clusters-dir PATH |
Override the cluster root directory from layout config | No override |
--base-ref REF |
Base ref used for merge-base comparison | master |
--cluster NAME |
Render and compare one specific cluster | Optional |
--all-clusters |
Render and compare all clusters | Optional |
--output-dir PATH |
Keep rendered manifests and diff files | Temporary dir otherwise |
--context-lines N |
Unified diff context lines | 3 |
--diff-mode raw|semantic|both |
Select raw diff, semantic diff, or both | semantic |
--output-format plain|markdown |
Select terminal output format | plain |
--project-id |
Override GitLab project ID for comment mode |
CI_PROJECT_ID |
--mr-iid |
Override GitLab MR IID for comment mode |
CI_MERGE_REQUEST_IID |
--gitlab-base-url |
Override GitLab API base URL for comment mode |
CI_API_V4_URL or CI_SERVER_URL |
The comment subcommand always renders markdown internally and updates a single sticky MR note. If the note body is already current, it leaves the note unchanged.
comment also supports:
--comment-mode full|summary|summary+artifacts--max-comment-bytes Nto trigger compact fallback for very large notes--validate=falseto skip offline validation
møbius ships embedded schema bundles under internal/validate/schemas and keeps the schema import manifest in schemasources.yaml.
Release-backed sources are resolved into concrete versions in schemas.lock.yaml. For GitHub-backed sources, schema-sync resolves latest to the current GitHub release tag and falls back to the latest repository tag when a project does not publish releases.
Runtime stays fully offline:
møbiusvalidates with rendered CRD schemas from the manifests under review when available- otherwise it uses schema files embedded from this repository
- it never fetches schemas while running
difforcomment
The maintenance workflow is:
make schema-sync
make schema-verifyUse this when adding new bundled schemas or refreshing the embedded bundle from repo-local source files or explicit URL sources.
Typical update flow:
- add or refresh schema source files, or update schemasources.yaml with explicit URLs
- run
make schema-sync - review the generated schema diff under internal/validate/schemas and the resolved versions in schemas.lock.yaml
- run
make schema-verify - commit the schema updates
- build
bin/møbius
As long as the schema files are already committed, building møbius on-prem only needs the checked-in source tree and Go dependencies.
møbius is distributed as a versioned Go CLI module at github.com/sohooo/moebius.
- local installation uses
go install github.com/sohooo/moebius/cmd/mobius@<version> - container releases are published as
ghcr.io/sohooo/moebius:vX.Y.Z - GitHub releases attach prebuilt CLI archives plus
checksums.txt - release tags should follow semver
- the current recommended series is
v0.x.ywhile CLI behavior and flags are still evolving - move to
v1.x.yonly when the CLI surface is intended to be stable latestis not published for container images during thev0series; use an explicit tag
For each release:
- run
make schema-verify - run
make verify - create a semver git tag on the default branch
- push the tag
- confirm the GitHub release was created with binary archives and
checksums.txt - confirm the GHCR image
ghcr.io/sohooo/moebius:vX.Y.Zwas published
The tag-driven release workflow also runs the verification steps, builds release archives for Linux and Darwin on amd64 and arm64, and publishes the matching GHCR image for the same tag.
møbius is a native Go CLI built to bin/møbius and published as the Go module github.com/sohooo/moebius.
It is self-contained at runtime and uses Go libraries for:
- Git repository access and merge-base resolution
- Helm chart loading and rendering
- YAML parsing and resource splitting
- raw unified diffs and semantic YAML diffs
bin/møbius is a generated build artifact and is ignored in Git.
The repository also includes a Dockerfile for building a small runtime image that installs the published CLI with go install, embeds release metadata, and ships only the resulting møbius binary plus CA certificates.