Souther compiles business models to Java types pinned to class version 25
Souther is a small JVM language for building closed, executable business models.
At a glance
- What is it?
- A small JVM language where invariants are checked at construction, rejections are ordinary values instead of exceptions, and examples are evaluated while the model compiles. The price is a hard Java 25 requirement on both sides of the build.
- Who is it for?
- Souther fits a team writing state machines where the set of valid values is known up front and wants the illegal states to be unrepresentable in generated Java, with a command that reports which inputs its examples do not cover. It does not fit a project that cannot move its build to JDK 25, because the class files it emits are pinned to version 25 and no newer runtime will read them.
- Can I use it commercially?
- Yes, with conditions. EPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Star history
- souther-lang/souther95 ★ · +61
| Repository | 2026-08-23 | 2026-10-23 |
|---|---|---|
| souther-lang/souther | 34 | 95 |
61 Stars in the last 61 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Java 25 is needed twice, not once
This is the constraint to read first, because it decides whether the project is a candidate at all. Souther requires JDK 25 to run, and an application consuming its output needs JDK 25 too. Generated `.class` files and `souther-runtime` are pinned to the Java 25 class-file version, and `raoh`, the artifact every derived decoder and encoder calls, is itself a Java 25 artifact.
That produces a split the documentation is blunt about: the Java that runs Souther and the Java a project's build runs on are separate questions, and a bundled runtime answers only the first. So the convenient answer of shipping a self-contained archive does not carry over to your build server, which still has to be on 25.
The generated code is ordinary Java that keeps the distinctions the model made, which is the appeal. The flip side is that the target is a moving, very recent platform, and this project also names `raoh` as a dependency without saying anything further about it.
brew, a Scoop bucket, install.ps1, or a zip you check yourself
Four routes, and they are not variations on one installer.
On macOS and Linux through Homebrew:
brew install souther-lang/souther/southerOn Windows through Scoop, which needs the bucket added first:
scoop bucket add souther https://github.com/souther-lang/scoop-souther
scoop install souther`install.ps1` is the Windows path without Scoop:
irm https://raw.githubusercontent.com/souther-lang/souther/main/install.ps1 | iexWhat that script does is specific enough to matter for a locked-down machine. It takes a release, holds it against the `SHA256SUMS` file published beside it, unpacks under `%LOCALAPPDATA%\Programs\souther` with a `current` link pointing at the version it just wrote, and puts that link on your `PATH`. It installs for one user, needs no administrator, and owns that one directory: uninstalling removes it and the single `PATH` entry it added and leaves the rest of `PATH` alone.
One catch with the pipe form: piping into `iex` passes no arguments, so asking for a particular version, for the build without a runtime, or for an uninstall means naming the script block instead. The script's own header says how.
The two Windows archives differ by one runtime, and both drop the class-data archive
On Unix there is one command to think about. `souther` is the whole command line, a launcher prepended to an uber jar; put it somewhere on `PATH` and it runs on a Java 25 it finds there.
Windows ships two archives instead. `souther-<version>-windows-x64.zip` carries a Java runtime of its own, so nothing has to be installed beside it, and the command inside is `souther\souther.exe`, which `jpackage` writes from the same jar the other archive runs. `souther-<version>-windows-x64-nojdk.zip` is that same command line without the runtime, for a machine that already has a JDK 25 and for a CI image that would rather not carry a second one. Its command is `souther\souther.cmd`, which reads `JAVA_HOME` and otherwise takes `java` from `PATH`.
Either archive unpacks to a single directory with the launcher at its root, so the directory to put on `PATH` is the same one. The part worth planning around is what neither archive carries: the class-data archive, so a compile on Windows costs what a first compile costs on Unix. If you assumed the bundled-runtime zip also shipped the warm class data, that assumption will show up as build time.
A JRE instead of a JDK fails quietly on every command but one
This is the failure mode the installation notes go out of their way to describe, and it is nastier than a stack trace.
The requirement is a JDK and not a JRE, because `souther japi` reads a library's javadoc out of its sources and reaches a compiler to do it. On a runtime without one, that command ends on a class it cannot find, and every other command answers as though nothing were missing. So the symptom is not a broken install. It is a `japi` invocation that stops partway through while `compile`, `init` and `examples` carry on as if the environment were correct.
The mitigation is already in the packaging. The `windows-x64.zip` archive bundles a runtime, and the Unix form looks for a Java 25 on `PATH`, so the honest check before you debug anything else is to confirm that the `java` on your `PATH` is a JDK 25 and not a runtime-only distribution.
For the manual route, the same discipline applies one level up. Every release attaches its artifacts to the GitHub Release page, and `SHA256SUMS` covers all of them, so `sha256sum -c SHA256SUMS` in the directory you downloaded into will tell you which files arrived intact.
Rejections are values, and constructs is the authority grant
The language model is easiest to read from its own worked example. A travel request either becomes `Submitted` or is rejected:
module example.trip
import String ( length )
data EmployeeId = String
invariant length(value) > 0
data Amount = Int
invariant value >= 0
data DraftRequest = { applicant: EmployeeId, plannedCost: Amount }
data Submitted = { ...DraftRequest, submittedAt: String }
data Rejected = { reason: String }
behavior submit : (request: DraftRequest, submittedAt: String) -> Submitted | Rejected
constructs Submitted, RejectedFive things are happening there. `data` declares domain values and states. `|` separates alternatives and `...` composes fields, which is how `Submitted` inherits the request and adds a timestamp. An `invariant` is checked every time that data is constructed, by a decoder or by a behavior, which makes construction the single place the constraint applies. A `behavior` declares its input and the business outcomes it can produce, and `constructs` is what grants it authority to build those values.
That last point is the design decision with teeth. A rejection is a branch written with `guard ... else ...`, and the rejected value is an ordinary domain value rather than an exception, so a caller can be held to the fact that it happened. The complete runnable version of this model is `businesstrip` in the separate examples repository.
Examples run at compile time, and souther examples admits what it cannot answer
The coverage story is the part that sets Souther apart from a test suite you write later, and it has a specific definition. An `example` is evaluated while the model compiles, and `souther examples` measures what those examples cover: which class of an input nothing stands in, which boundary value nothing sits at, and which rule of a body nothing goes through.
The behaviour on failure matters as much as the measure. Where it cannot answer, the command says what the question is still open on, rather than reporting a clean result. A coverage tool that quietly returns success when it has no evidence is worse than no tool, because you wire it into a check and the check always passes. This one is built to tell you it does not know.
The intended use is therefore pre-commit rather than post-hoc. Examples live next to the model they constrain, get checked by the compiler that would otherwise produce a wrong value, and a coverage question that stays open is a visible gap rather than a forgotten one.
souther init writes a project; inside an existing build it only adds lines
`souther init` writes a project rather than leaving you to copy an example. It takes a coordinate, a group and an artifact you decide, and writes a build that already declares the Souther plugin plus one `.sou` holding a model with `example` rows covering it, so the first compile checks those rows and `souther examples` answers immediately:
souther init com.example:hello
cd hello && mvn compile`--build gradle` writes a Gradle build instead. Run inside a project that already has a `pom.xml` or a `build.gradle.kts`, it reads the coordinate out of that build and adds a source directory and the plugin declaration to it. Nothing already written is overwritten, and what it left alone it reports.
The two plugin ecosystems differ in one detail worth knowing before you wire a build. `souther-maven-plugin` takes the Souther to compile with from the `souther-runtime` dependency the pom already declares, while the Gradle plugin expects a project with a model to name the version as `southerVersion`. Both are released from their own repositories, and either compiles `.sou` files under `src/main/souther` into the classes the rest of the build reads.
Eleven modules and an AsciiDoc specification in one repository
The tree shows what the tool actually is: a compiler with a full toolchain around it. The named modules are `souther-compiler`, `souther-cli`, `souther-runtime`, `souther-syntax`, `souther-fmt`, `souther-lsp`, `souther-bench`, `souther-architecture-test`, `souther-build-driver`, `souther-test-support` and `souther-program-api-test`. A formatter and a language server existing in the first three releases is the interesting part of that list, because both are tools you use daily rather than machinery you install once.
Alongside them sit `specification.adoc` and a `syntax/` directory, which is the answer to a question worth asking about any language at version 0.3: the model is defined somewhere outside the compiler source. There is also a `CLAUDE.md`, a `SECURITY.md` and a `CONTRIBUTING.md` at the root, plus `install.ps1` living in the repository rather than in a release asset bucket.
On maintenance, the release line moved fast: v0.1.0 on 2026-08-29, v0.2.0 on 2026-09-14, v0.3.0 on 2026-09-28. The last push was on 2026-09-30, two days after that release. Licence is EPL-2.0, which is a weak-copyleft licence and a different choice from MIT or Apache-2.0 for a tool that generates code into someone else's repository, so check that against your own policy rather than assuming.
Editorial conclusion
Souther fits a team writing state machines where the set of valid values is known up front and wants the illegal states to be unrepresentable in generated Java, with a command that reports which inputs its examples do not cover. It does not fit a project that cannot move its build to JDK 25, because the class files it emits are pinned to version 25 and no newer runtime will read them. Verify four things before adopting it: that your consumers can compile against Java 25, whether you install the Windows archive with or without its bundled runtime, that `souther japi` finds a compiler, and that the independent model specification in `specification.adoc` covers the rules you intend to write. The licence is EPL-2.0, v0.3.0 shipped on 2026-09-28 and the last push was 2026-09-30.
Frequently asked questions
What Java version does Souther need?
JDK 25 to run, and JDK 25 to consume the output. Generated .class files and souther-runtime are pinned to the Java 25 class-file version, and raoh, which every derived decoder and encoder calls, is a Java 25 artifact.
How do I install Souther on Windows without administrator rights?
Use install.ps1, which installs for one user and needs no administrator. It unpacks under %LOCALAPPDATA%\Programs\souther with a current link on your PATH, and an uninstall removes that directory and the one PATH entry it added.
What is the difference between the two Souther Windows zip archives?
souther-<version>-windows-x64.zip bundles its own Java runtime and the command is souther\souther.exe, while souther-<version>-windows-x64-nojdk.zip expects a JDK 25 already and its command souther\souther.cmd reads JAVA_HOME or takes java from PATH.
How does Souther model a rejected request?
As an ordinary domain value rather than an exception. A behavior declares its input and possible outcomes, constructs grants it authority to build those values, and guard ... else ... writes the rejection branch, so a caller can be held to the fact that it happened.
What does souther examples actually measure?
Which class of an input nothing stands in, which boundary value nothing sits at, and which rule of a body nothing goes through. Where it cannot answer a question, it reports the question as still open rather than returning a clean result.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/souther-lang-souther)Star history chart for your README
[](https://hysenlabs.com/projects/souther-lang-souther)Was this useful?