25 independent libraries. Enforced FC/IS architecture. One coherent stack, zero lock-in.
Stop stitching together libraries. Every component follows the same patterns, tests the same way, and swaps via configuration.
Every Wagoe module follows Functional Core / Imperative Shell. The directory structure makes clean architecture the default — not a convention that erodes over time.
shell/ports.cljcore/Enforced by directory layout + clj-kondo rules · Every library follows the same structure
Each library is a standard deps.edn dependency, independently publishable to Clojars.
# Natural language module generation $ bb scaffold ai "order module with customer, total, status" ✓ Schema defined schema.clj ✓ Validation rules core/validation.clj ✓ Persistence layer shell/persistence.clj ✓ HTTP routes shell/routes.clj ✓ Service layer shell/service.clj ✓ Tests generated test/core_test.clj Generated 6 files in libs/order/ All tests passing: 12/12
(ns wagoe.order.schema (:require [malli.core :as m])) (def Order [:map [:id :uuid] [:customer-id :uuid] [:total [:and :decimal [:> 0]]] [:status [:enum :pending :paid :shipped :delivered]] [:created-at :instant]])
(defworkflow order-workflow {:initial-state :pending :states #{:pending :paid :shipped :delivered :cancelled} :transitions [{:from :pending :to :paid :required-permissions [:finance]} {:from :paid :to :shipped :guard :payment-confirmed} {:from :shipped :to :delivered}]}) ; Pure core logic — no I/O, no mocks needed
The entire state machine lives in core/ — no I/O, no side effects. Test every transition without a database or mock.
Every state change is recorded with who, when, and from/to state. Query with plain SQL.
Role-based guards and custom guard functions. The workflow rejects invalid transitions at the transition layer.
;;; Development — zero setup, zero config {:wagoe/db-context {:adapter :sqlite :db "dev.db"} :wagoe/cache {:adapter :in-memory} :wagoe/observability {:log-adapter :stdout :err-adapter :no-op}} ;;; Production — one key change each. Zero code changes. {:wagoe/db-context {:adapter :postgresql :host #env DB_HOST :pool-size 10} :wagoe/cache {:adapter :redis :uri #env REDIS_URL} :wagoe/observability {:log-adapter :datadog :err-adapter :sentry :dsn #env SENTRY_DSN}}
;;; Cross-cutting concerns declared alongside the route. {:path "/api/admin/orders" :methods {:post {:handler 'handlers/create-order :interceptors ['auth/require-admin 'audit/log-action 'rate-limit/admin 'metrics/record-latency]}}} ;;; Service layer — one macro call, all telemetry automatic (defn create-order [this order-data] (service/execute :create-order {:order order-data} (fn [{:keys [params]}] (order-core/prepare (:order params))))) ; Automatically instruments: structured logs, metrics, ; Sentry breadcrumbs, PII redaction. No telemetry code needed.
Kit, Phoenix, Django, and Rails all require you to assemble and wire the pieces yourself. Wagoe ships FC/IS enforcement, auto-admin UI, multi-tenancy, state machine workflows, full-text search, report generation, PII redaction, and framework-aware AI tooling — built in, consistent, following the same patterns across all 25 libraries.
Numbers based on comparing Wagoe to assembling a custom Clojure stack from scratch.
The ROI compounds. Small teams ship faster. Growing companies scale without chaos. Enterprises govern without mandates.
wagoe command.wagoe add payments.wagoe new already generated .env with a real JWT_SECRET.Follow development on GitHub and chat on Clojurians Slack.