(defn ^:deprecated enqueue-in-tx!
"DEPRECATED: use the ITransactionalQueue port instead.
Removed no earlier than the next major release."
[& args]
...)
This page states what you can rely on, what you cannot, and how a change that
breaks you will reach you. It describes the framework as it is today — Wagoe is
at its release candidate for 1.0.0, and the surface below is the one 1.0.0
will promise.
Current version |
|
Stability | Release candidate. The |
Artifacts | 31 libraries on Clojars, all in the |
Versioning | Lockstep — every library carries the same version and is released together |
Java baseline | JDK 21. Not a recommendation: the installer refuses an older JDK, the images
build and run on 21, and every CI job that starts a JVM uses it.
|
Lockstep versioning means you never have to work out which wagoe-user goes
with which wagoe-platform: matching version strings are always compatible with
each other. It also means a library gets a version bump when it has not changed,
because something else in the suite did.
Releases were 1.0.0-beta-N, incrementing N per release, and are now
1.0.0-rc-N on the way to 1.0.0. Both replaced the older 1.0.1-alpha-N
scheme.
| Last alpha | First beta | Date |
|---|---|---|
|
| 2026-07-19 → 2026-07-23 |
|
The version number went down. Under Maven ordering If you use a version range or any tool that resolves "newest", it will prefer the
last alpha over every beta. Pin exact versions. The |
The old scheme was wrong in a way worth naming, since it is the reason for the
change: 1.0.1-alpha-41 reads as a patch release of a shipped 1.0. Nothing
called 1.0 had ever been released. 1.0.0-beta-N says what is true — work
leading up to a first 1.0.0.
So that it cannot happen again:
A pre-release is always <major>.<minor+1>.0-<stage>-N — 1.1.0-alpha-1,
1.1.0-rc-2. Never from a patch version.
Patch versions are only ever final. There is no 1.0.1-alpha-1.
The reason is Maven’s ordering, which puts 1.0.1-alpha-1 above 1.0.0: a
pre-release of a patch outranks the release it precedes, for anyone resolving
"newest". A pre-release of the next minor sorts below that minor and above
everything already out, which is what a pre-release should do.
bb bump refuses the first shape and bb deploy --check-versions — which the
publish workflow runs before any upload — refuses to publish under it.
|
|
Wagoe is hexagonal, and the architecture already draws the line this policy needs. The supported surface is the seam, not the implementation behind it.
| Surface | Where | Supported? |
|---|---|---|
Protocols |
| ✅ Yes — this is the contract |
Schemas |
| ✅ Yes |
Integrant keys |
| ✅ Yes |
Configuration | Keys read from | ✅ Yes |
CLI + Babashka commands |
| ✅ Yes |
Functional core |
| ❌ No — internal, may change in any release |
Imperative shell |
| ❌ No — internal; depend on the port, not the adapter |
The practical rule: if you can reach it through a protocol, a schema, an
Integrant key or a config key, it is supported. If you are calling into
core/ or shell/ directly, you are using an implementation detail, and
bb check:ports exists precisely to stop the framework’s own code from doing
that.
ports.cljMost libraries put their protocols in one wagoe.<lib>.ports. Four deviate by
design, and the rule above still applies — only the file layout differs.
| Library | Where its contract lives |
|---|---|
|
|
| One |
| Has no |
| Has no ports and no schema. It is a library of pure Hiccup primitives, so
the public surface is the functions in |
wagoe-mcp is a fifth deviation, but only in naming: its sources live under
wagoe/mcp/ (namespaces wagoe.mcp.*) while the directory is libs/wagoe-mcp.
Its ports namespace is where you would expect.
This is not a hypothetical distinction. wagoe-user dropped five protocols from
its ports.clj in one release, and wagoe-jobs moved a transactional-enqueue
capability from a namespace function onto a port in another. Both were breaking
changes to the supported surface — which is exactly why they belong in a policy
rather than a commit message.
The surface is frozen. 1.0.0 is 1.0.0-rc-1 plus whatever the candidate
turns up; nothing further lands under # Breaking before the tag.
Breaking changes that already shipped are in CHANGELOG.md under a
# Breaking heading, naming the affected library and the migration.
Deprecations are announced under # Deprecated.
We will not remove something in the same release that first deprecates it, unless it is broken enough that leaving it in place is worse. That case is called out explicitly.
Semantic Versioning, applied to the public surface defined above.
A breaking change requires a major version.
Anything removed in a major version must have been deprecated in a prior minor version, and must have been deprecated for at least one minor release and 90 days, whichever is longer.
Deprecated vars carry ^:deprecated metadata with a pointer to the
replacement, so your editor and clj-kondo can flag them.
The promise above covers stable libraries. A second tier, incubating, is published and usable but outside the breaking-change guarantee, because we already know its API is not finished. Saying so is cheaper for you than a major version bump for a fix we could see coming.
| Library | Why |
|---|---|
| The Mollie adapter throws "not implemented yet" for |
| 263 lines of source against 37 of test, on the boot path of every application |
| Five providers, no sweep proving they answer alike |
| Three geocoding providers, same gap |
| Three adapters — SMTP, IMAP, Twilio — same gap |
| Three exporters, same gap |
| The newest library here, and the least exercised |
| Its guard and transition API is still moving |
Everything else published is stable. wagoe-tools, wagoe-devtools, wagoe-cli
and wagoe-mcp are tooling and carry no tier — see What is not covered below.
A library is promoted when two things are true: every port with more than one
adapter has a sweep that runs the same assertions against each of them, and its
documentation matches what it does — a README, a page on this site, and an
AGENTS.md that is not describing an older shape. Promotion is not a breaking
change and can happen in any release; demotion cannot happen at all, because a
stable library that turns out to need a break gets the major version instead.
wagoe list modules and wagoe add print the tier, so you learn it before you
depend on it rather than from this page afterwards.
wagoe-tools, wagoe-devtools, wagoe-cli and wagoe-mcp are development
tooling. They are versioned in lockstep and published to Clojars, but their
internal namespaces are not an API — the commands are.
Generated code. The scaffolder’s output becomes yours; we change the generator, not your files.
Database schemas of the framework’s own tables, other than through migrations we ship.
:wagoe/http-server starts Jetty through ring/ring-jetty-adapter (Jetty 12).
That is a decision, not a default that nobody wrote down:
It is the adapter the Ring maintainers ship and support themselves, which matters more to a framework with a stability promise than a benchmark does.
It carries the standard Ring WebSocket API that wagoe-realtime is built on,
HTTP/2, async handlers for streaming responses, and a virtual-thread executor.
Nothing on the roadmap needs a capability Jetty lacks.
The alternatives each cost something without solving a problem we have: http-kit has its own WebSocket API and no HTTP/2; Aleph brings Netty and a second concurrency model; Undertow adds nothing over Jetty 12.
What this means for the promise: there is no server port. :wagoe/http-server
is Jetty, its options map is Jetty’s, and swapping the server is not a supported
configuration. If a real need for another server appears, the answer is a port
with a conformance suite — the same route every other adapter in the framework
takes — not a config flag.
A deprecation is three things, and it is not a deprecation without all three:
^:deprecated metadata on the var, protocol or method, with a docstring line
naming the replacement.
A # Deprecated entry in CHANGELOG.md for the release that introduced it.
A replacement that exists and is documented at the time of the announcement.
(defn ^:deprecated enqueue-in-tx!
"DEPRECATED: use the ITransactionalQueue port instead.
Removed no earlier than the next major release."
[& args]
...)
An Integrant component key cannot carry metadata, so for one the first point is
a WARN on init naming the replacement. A changelog entry that the running
system says nothing about is an announcement to whoever already read it.
CI enforces the second point: a var carrying ^:deprecated that CHANGELOG.md
never names fails the build.
Everything currently deprecated, and what replaces it. None of these is removed
in a 1.x release.
| Deprecated | Use instead |
|---|---|
|
|
The | Nothing — admin’s components take the settings map directly. |
The |
|
|
|
Do not confuse library stability with the HTTP API versioning your application exposes to its own clients. Those are different axes and Wagoe handles them separately.
For your endpoints, the platform ships version lifecycle support — deprecated
version sets, sunset dates, and an X-API-Deprecated response header — in
wagoe.platform.shell.http.versioning. Routes are mounted under /api/v1 by
default. That machinery governs the contract between your app and its
clients; this page governs the contract between Wagoe and you.
If a release breaks you and the break is not in CHANGELOG.md, that is a bug in
this policy as much as in the code. Open an issue on
GitHub with the two versions and the failure —
an unannounced break gets a fix or a revert, not a workaround.
Can you improve this documentation? These fine people already did:
thijscreemers & Thijs CreemersEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |