If you build it: auth, admin UI, jobs, search and multi-tenancy are already wired, so you start at the business logic. If you run the team: every module has the same shape, enforced in CI. If you need it shipped: the first working version lands in days, on infrastructure you already have. Below is what that looks like in practice — 28 libraries, one architecture, and an honest answer to whether a Clojure framework is a good idea.
If you're a solo developer who owns the whole codebase and genuinely enjoys making architectural decisions fresh each project, Wagoe adds friction, not value. It's built for teams and systems that need to stay consistent over years — where onboarding time, cross-team refactoring, and long-term maintainability have real costs.
The Clojure community is right to be skeptical of frameworks. Here's the direct answer.
The question isn't "framework vs. no framework." It's "explicit conventions vs. implicit conventions." Every serious Clojure backend already has the latter. Someone decided that business logic lives here and I/O lives there. Someone decided how snake_case converts at the database boundary. Someone documented why the service layer is structured the way it is — or didn't, and now that knowledge lives in one person's head.
Wagoe makes those decisions explicit, enforced, and consistent across every module and every team member. The enforcement is worth examining: bb check:fcis runs as a pre-commit hook and in CI. It will fail your build if a core/ namespace imports anything from shell/, any I/O library, or a logging framework. That's not magic — it's a clj-kondo rule and a Babashka script. You could write it yourself. Wagoe just ships it so you don't have to.
If "architecture library" resonates more than "framework," that framing works too. Wagoe is opinionated about structure, not about which libraries power it — each wagoe-* artifact is a standard deps.edn dependency you can adopt one at a time. Your existing Integrant, Reitit, and next.jdbc code doesn't go away. Wagoe provides the connective tissue and enforces the pattern.
Capabilities that usually arrive as a hosted service or a stack of community libraries are Wagoe libraries instead — running on the infrastructure you already have.
| Capability | Commonly solved with | Wagoe library | What it runs on |
|---|---|---|---|
| Authentication, MFA, RBAC | Auth0, Clerk | wagoe-user | Your database |
| Background jobs and retries | Inngest, Temporal | wagoe-jobs | Redis |
| Admin / CRUD interface | Retool, Forest Admin | wagoe-admin | Your app process |
| Full-text search | Algolia, Elastic Cloud | wagoe-search | PostgreSQL FTS |
| Error tracking and metrics | Sentry, Datadog | wagoe-observability | Pluggable backend |
Each of these is a plain deps.edn dependency. Where a hosted service suits you better, the port abstraction lets you keep it — wagoe-observability ships a Sentry adapter for exactly that reason.
Generic AI tools can write Clojure. Wagoe makes those tools produce code that's architecturally correct, immediately mergeable, and consistent with everything already in the codebase. The reason is structural, not magical.
AI assistants generate better code in codebases they can predict. Every Wagoe module follows the same layout: core/ for pure logic, shell/ for side effects, ports.clj for contracts, schema.clj for validation. When every module looks the same, a tool that has seen one can correctly generate, refactor, or extend any other — without learning project-specific conventions. It also avoids the most common AI mistake in FC/IS codebases: accidentally putting a database call inside a core/ function.
Every library in Wagoe ships an AGENTS.md alongside the README. These files are written for AI coding agents — Claude Code, Cursor, Copilot — not for humans reading at 2am. A README explains what a library does. An AGENTS.md explains which layer owns which responsibility, which pitfalls cause runtime errors, and what correct patterns look like with annotated examples. This is a design choice, not an afterthought: the primary consumer of detailed technical documentation in 2026 is often an AI agent.
Malli schemas are machine-readable by design. An AI assistant that can read a schema knows exactly what data is valid, what fields are optional, what the constraints are, and what transformations are needed at the persistence boundary. When bb ai sql generates a HoneySQL query, it reads the actual Malli schemas for the relevant modules to understand the data model — rather than inferring from function signatures or guessing column names. The schema is the single source of truth, and it's parseable.
wagoe-ai understands Wagoe's conventions, not just Clojure syntax. NL scaffolding: bb scaffold ai "invoice module with number, line items, total, status" generates a complete FC/IS-compliant module in under a minute. Error explainer: reads Clojure stack traces with Wagoe-specific context. Test generator: produces unit test namespaces for core/ functions. SQL copilot: natural language → HoneySQL. Offline-first: runs via Ollama by default — no data leaves your machine unless you explicitly configure a cloud provider.
$ wagoe new my-app ✓ Project created: my-app/ AI-ready: CLAUDE.md, AGENTS.md, a Claude Code skill, and a wired MCP server (.mcp.json) are included. $ cd my-app $ bb setup --database sqlite --ai-provider replicate ✓ Generated resources/conf/dev/config.edn $ bb quickstart [4/8] Scaffolding sample module [8/8] Verifying project structure ━━━ Quickstart Complete ━━━━━━━━━━━━━━━ $ bb scaffold ai "product module with name, price, stock" --yes ✓ Successfully generated module: product $ clojure -M:test --focus my_app.product.core.product-test 0 failures. $ bb scaffold integrate product $ bb migrate up $ bb repl user=> (go)
A real run against the released v1.0.0-beta-8: the project
arrives with CLAUDE.md, AGENTS.md, a Claude Code
skill and a wired MCP server; then bb scaffold ai turns one
sentence into a module, and its schema and tests are on screen before it
boots.
A full project, running, in under five minutes — then decide.