Back to blog
2026-09-28 Thijs Creemers

Release: v1.0.0 — stable, and what that promises you


Wagoe 1.0.0 is out. If you have been waiting for a version you can build on without reading every changelog for breaks, this is it. Semantic Versioning now applies to the public surface: ports, schemas, :wagoe/* component keys and their options, configuration, and the CLI commands.

It is a new 1.0, not a mature one. Your first project will find things we haven’t. The promise is about how a fix reaches you, not that there will be none.

What you can rely on from here

  • A breaking change to the public surface needs a major version. Nothing in 1.x breaks code written against a stable library in 1.0.0.

  • Nothing is removed without warning. A removal in 2.0 must be deprecated in a 1.x minor first, for at least one minor release and 90 days, whichever is longer. Deprecated vars carry ^:deprecated metadata naming the replacement, so your editor and clj-kondo flag them.

  • Every library carries the same version. wagoe-user 1.0.0 goes with wagoe-platform 1.0.0; you never work out a compatibility matrix.

  • Generated code is yours. The scaffolder’s output is not covered — we change the generator, never your files.

Eight libraries are published as incubating and sit outside the guarantee, because we already know their API is not finished: payments, config, ai, geo, external, reports, audience and workflow. Saying so now is cheaper for you than a 2.0 for a fix we can see coming. wagoe list modules and wagoe add print a library’s tier, so you learn it before you depend on it. The stability page gives the reason for each, and what promotes a library to stable.

Pin exact versions. The discontinued 1.0.1-alpha-42 still sorts above 1.0.0 under Maven ordering, so a version range or anything resolving "newest" picks the old alpha. Pre-releases from here are cut from the next minor — 1.1.0-rc-1, never 1.0.1-alpha-1 — so this cannot happen again.

Breaking: three, in 1.0.0 itself

The release candidates said a break would land in an RC, never in 1.0.0. Three did anyway, rather than promise, for the life of 1.x, a shape we already knew was wrong. The list for 1.0.0 closes at twenty-eight. Each is under # Breaking in the changelog.

  • Every JSON error body is {"error": {"type": …, "message": …}}. Refused input is validation-error. Read error.type and error.message; details and correlation-id moved inside error.

  • A write a unique or foreign key refuses is 409 conflict naming the field, on H2, SQLite and PostgreSQL. It was a 500. A scaffolded API answered a missing reference with 400: read 409.

  • A scaffolded API refuses a delete or move below --min with 409 conflict, as the admin does. It was 400. Only regenerated service files change; an existing module keeps its 400.

Fixed: a client’s mistake is not a 500

The one error shape came out of a pass over every endpoint asking what a client’s mistake answers. Too often it was a 500, sometimes with exception text in it:

  • An unknown admin entity, and a workflow admin id that is not a UUID, answer 404.

  • Profile preferences, password and MFA setup answer 400 or 404 for bad input or a deleted user.

  • The MFA endpoints no longer put an exception’s text in a 400.

  • Audience `422`s send the fields' messages, not the whole Malli schema.

  • The search API reads the body it is sent; indexing answered 500, and a search ran for "".

  • The audit log page works on H2.

  • A duplicate unique value in the admin marks the field instead of saying "Failed to create Invoice".

Fixed: bb db:reset, bb db:seed and bb setup

  • bb db:reset kept users, sessions and tenants. It now drops everything the app owns, then migrates — and only in an explicitly named dev, test or acc, confirmed by the database name. Prod changes through migrations. --help prints usage instead of running the reset.

  • bb db:seed runs where bb db:reset does, honours bb db:seed path/to/file.edn, and says what each seed hook did: "Started 3 workflow instances (invoice-workflow)".

  • bb setup --prod true … --ai-provider x exited 1. It writes the rest and leaves AI out of prod, and its next steps name the variables prod actually reads.

  • bb doctor sees a user module switched on in :extra-modules, and treats an unset REDIS_PASSWORD as a warning, not a failure.

  • bb ai admin-entity and bb scaffold ai refuse without a terminal unless you pass --yes; --force never prompts.

  • A bb scaffold wizard’s Command: line pastes back — it is shell-quoted now.

Fixed: workflows and the admin

  • A workflow transition answered "available-transitions": null, in the workflow API and a scaffolded /:id/transition. Both now list what the caller may do from the new state.

  • The workflow boot put a unique index on workflow_instances in production. It changes that table only in dev, test and acc now; elsewhere it warns you to run bb migrate up.

  • Admin toasts named one record in the plural, "Invoices created successfully". One record is singular, and translated; set :label-singular where the automatic singular is wrong.

  • Every boot logged each full CREATE TABLE at INFO. DDL is DEBUG now. Copy the migratus.database logger from wagoe new’s `logback.xml.

  • A dev server on HTTP_PORT=3200 logged "searching ports 3000-3099". The log names the port requested and the port bound.

  • Every bb guide topic matches the code, and bb guide seed explains the seed file.

Added: seed data that writes itself

  • The seeder fills in id, created-at and updated-at, and a child names its parent by a symbolic id: :id :invoice/acme on the parent, :invoice-id :invoice/acme on the child.

  • bb scaffold generate and entity add a commented example per entity to resources/seeds/dev.edn. Uncomment one to seed it; existing seeds are kept.

  • workflow_instances.entity_uuid holds the entity id as a UUID, indexed. Join on it instead of casting entity_id. migrate up adds it, rewriting the table once on PostgreSQL.

Version alignment

All 31 artifacts bumped to v1.0.0 to maintain lockstep versioning.

Upgrade

Re-run the installer to pick up the latest release:

curl -fsSL https://get.wagoe.org | bash

Coming from rc-4, in this order:

  1. Pin 1.0.0 exactly in deps.edn, not a range.

  2. Run bb migrate up to add entity_uuid. On PostgreSQL it rewrites workflow_instances once; plan for that on a large table.

  3. API clients read error.type and error.message, and expect 409 where a unique or foreign key refuses a write.

  4. Logging: copy the migratus.database logger from a fresh wagoe new project’s logback.xml.

  5. Scripts that drive bb ai admin-entity or bb scaffold ai without a terminal pass --yes or --force.

Coming from an earlier candidate, work through the rc-4 upgrade list first.