ddd CLI is the fastest way to start a ddd_cqrs_es application and keep generated projects consistent as they grow.
It is published by the ddd-cqrs-es-cli crate, installs a binary named ddd, and is released with the same version as ddd_cqrs_es.
Use it for:
- new app scaffolding with opinionated presets
- fine-grained additions like events, commands, routes, projections, and tests
- capability wiring for Redis, gRPC, tracing, snapshots, and idempotency
- Spin runtime command resolution
- agent/MCP workflows that need deterministic dry-run JSON before writing files
Install
Install the published CLI:Quick Start
Fullstack SaaS product (recommended starter)
Scaffold the production Spin + Leptos + wasi-auth template (same tree asexamples/fullstack-app):
ddd serve on a fullstack project resolves to make dev transport=both (Spin
plus the outbox worker so verification mail can deliver). Use make spin
only when you intentionally want the app without mail delivery.
What works after fullstack init
Product domain aggregates live beside the wasi-auth shell under
src/domain/.
ddd add aggregate also wires a demo application service and REST under
/api/domain/{module}/… (process-local InMemoryEventStore — swap for durable
storage before production; routes are not Cedar-gated by default). Stock
examples/fullstack-app stays domain-free; dual-sync excludes src/domain/,
src/domain_app/, and src/domain_rest.rs.
Domain-only or thin Leptos app
Create a small domain-only project:Command Model
Every command supports the same global controls:
The main command groups are:
Presets
Choose a preset withddd init --preset <preset>.
Examples:
spin.
The fullstack preset is intentionally fullstack; it defaults to
transport=both and ui=leptos, and rejects narrower transport/UI shapes.
Generated fullstack projects include the same Leptos, REST, gRPC, storage,
OAuth, passkey, organization, administration, audit-stream, smoke-test, and rollout surface as the reference
examples/fullstack-app app. They also include spin.production.toml.example
with exact OAuth/database outbound hosts to use as the production hardening
starting point. The generated Makefile includes oauth-credentials,
oauth-preflight, oauth-evidence, oauth-dev-browser-smoke,
oauth-browser-smoke, oauth-callback, browser-smoke, and
passkey-browser-smoke targets for local OAuth UI regression checks, live
provider readiness, redacted event evidence, callback evidence, page checks,
and WebAuthn checks. Generated manifests depend on the single wasi-auth
crate plus ddd_cqrs_es; they never contain cross-repository path dependencies.
This source checkout uses .cargo/config.toml patches only for local alpha
verification, while generated projects retain publishable registry manifests.
Generated Manifest
Every generated project includesddd.toml. The CLI uses this file to know what it can safely patch later.
Example shape:
AUTH_ENABLE_PASSKEYS=true. Configure
AUTH_PASSKEY_RP_ID, AUTH_PASSKEY_RP_NAME, AUTH_PASSKEY_ORIGIN, and
AUTH_PASSKEY_CHALLENGE_TTL_SECONDS in .env or Spin variables before testing
WebAuthn in a browser. For local browser passkeys, use localhost as the RP ID
and visit http://localhost:3008, not the numeric loopback URL.
AUTH_PRODUCTION_MODE=false keeps the generated stack simple for local
development. Set AUTH_PRODUCTION_MODE=true only with a pre-provisioned
AUTH_JWT_KEY_RING_JSON containing ES256 keys, HTTPS secure cookies, CSRF
secrets, and a production mail adapter. Administration is derived exclusively
from an MFA-authenticated VerifiedAuthContext; there is no admin-token field
or header. Production mode rejects runtime HS256 defaults, capture mail, and
missing secrets.
Generated fullstack projects also expose AUTH_COOKIE_SECURE. Keep it
false for local HTTP development and set it to true for HTTPS deployments
so browser sessions are issued with Secure, HttpOnly, and SameSite=Lax.
The generated Makefile and Spin manifests pass the declared auth variables into
the runtime component; changing JWT, OAuth, passkey, cookie, or
public-base-url values in .env or Spin variables is intended to affect the
running auth stack.
If a project does not have ddd.toml, treat it as outside the supported generated-project patching path unless you intentionally adopt it.
Add Domain Code
Runddd add ... from the generated project root, or pass --cwd <project>.
Add a second aggregate:
name:RustType. The CLI inserts generated variants into marker regions in the generated domain module and updates ddd.toml.
Available add targets:
Enable Capabilities
Useddd enable ... when the project exists and you want to wire a capability into ddd.toml and, where applicable, Cargo.toml feature flags.
Runtime Matrix
The CLI currently scaffolds Spin-focused apps. Supported values:
Use the CLI to inspect the live matrix:
db=redismeans Redis is the durable event/checkpoint/read-model store.realtime=redismeans Redis is only the wake/notification transport unlessdb=redisis also selected.
transport=http, transport=grpc, and transport=both.
Serve, Watch, and Fresh
The runtime commands read fromddd.toml and can be overridden with flags.
Preview the command:
fresh is reset-only. It should not start the server.
Agent and MCP Workflow
Agents should use JSON dry-runs before changing files:- Run
ddd capabilities --json. - Run
ddd matrixif runtime/backend choices matter. - Run the mutating command with
--dry-run --format json. - Inspect
operations. - Apply the same command without
--dry-run. - Run
ddd check. - Run project tests.
File and Symbol Targeting
The current CLI targets generated projects throughddd.toml, aggregate names, and marker regions.
This syntax is not currently implemented:
ddd.
Release Pairing
The library and CLI are versioned together. For maintainers:cargo login first, or provide CARGO_REGISTRY_TOKEN in the environment.
The release script validates that ddd_cqrs_es and ddd-cqrs-es-cli have matching versions, then publishes ddd_cqrs_es before ddd-cqrs-es-cli.
Troubleshooting
ddd check fails with missing generated files:
- Run it from the generated project root or pass
--cwd <project>. - Confirm
ddd.toml,Cargo.toml, andsrc/domain/mod.rsexist.
ddd add event cannot find an aggregate:
- Use the aggregate name from
ddd.toml. - Run
ddd add aggregate <Name>first if the aggregate does not exist.
--runtime wasmtime is rejected:
- The CLI-generated runtime is currently Spin-only.
- Use
spin, or checkddd capabilities --jsonafter upgrading the CLI.
- Inspect the file before using
--force. - Prefer dry-run JSON to see exactly which path is colliding.