Skip to main content
The 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:
Check that it is available:
When developing this repository locally, use the workspace binary instead:
For example:

Quick Start

Scaffold the production Spin + Leptos + wasi-auth template (same tree as examples/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:
Add a domain event:
Add a command:
Preview any write before applying it:
The dry-run output reports the planned file operations without changing files.

Command Model

Every command supports the same global controls: The main command groups are:

Presets

Choose a preset with ddd init --preset <preset>. Examples:
Current CLI-generated apps are Spin-focused. The runtime value is 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 includes ddd.toml. The CLI uses this file to know what it can safely patch later. Example shape:
Fullstack projects also include stable auth and authorization configuration sections. Provider entries reference environment variable names only; the CLI never writes OAuth client secrets into source files. Passkeys are disabled by default until 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

Run ddd add ... from the generated project root, or pass --cwd <project>. Add a second aggregate:
Add an event to an existing aggregate:
Add a command:
Field syntax is name:RustType. The CLI inserts generated variants into marker regions in the generated domain module and updates ddd.toml. Available add targets:
Common examples:

Enable Capabilities

Use ddd enable ... when the project exists and you want to wire a capability into ddd.toml and, where applicable, Cargo.toml feature flags.
Use dry-run JSON before enabling a capability in automation:

Runtime Matrix

The CLI currently scaffolds Spin-focused apps. Supported values: Use the CLI to inspect the live matrix:
Redis has two separate meanings:
  • db=redis means Redis is the durable event/checkpoint/read-model store.
  • realtime=redis means Redis is only the wake/notification transport unless db=redis is also selected.
Spin supports transport=http, transport=grpc, and transport=both.

Serve, Watch, and Fresh

The runtime commands read from ddd.toml and can be overridden with flags. Preview the command:
Serve the app:
Watch and restart:
Reset data only:
fresh is reset-only. It should not start the server.

Agent and MCP Workflow

Agents should use JSON dry-runs before changing files:
The report includes:
A safe agent loop is:
  1. Run ddd capabilities --json.
  2. Run ddd matrix if runtime/backend choices matter.
  3. Run the mutating command with --dry-run --format json.
  4. Inspect operations.
  5. Apply the same command without --dry-run.
  6. Run ddd check.
  7. Run project tests.

File and Symbol Targeting

The current CLI targets generated projects through ddd.toml, aggregate names, and marker regions. This syntax is not currently implemented:
If you need path or symbol targeting, add explicit CLI support and tests first, or patch the file manually with Rust-aware edits. Do not pass unsupported selector syntax to ddd.

Release Pairing

The library and CLI are versioned together. For maintainers:
Reliable publish dry-run forms are:
Real publish:
Run 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, and src/domain/mod.rs exist.
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 check ddd capabilities --json after upgrading the CLI.
A file already exists:
  • Inspect the file before using --force.
  • Prefer dry-run JSON to see exactly which path is colliding.