Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Commands

ddl init

Bootstrap the charly-vibes toolset.

ddl init
# Interactive mode — prompts for tool selection, confirmation

ddl init --yes
# Non-interactive mode — installs all tools, no prompts

ddl init --tools wai,dont
# Selective install — only the specified tools

ddl init --no-install
# Configure only — skip installation, just set up .ddl/

ddl init --gates
# Wire the end state users actually ask for: lefthook hard gates
# (pre-commit: ah check, pretender gate, spk lint; pre-push: ah check),
# .gitignore entries for tool data dirs (.testaruda/, .pretender/), and
# beads no-db stamping. Also orders tool inits so openspec runs before ah.
# Idempotent — safe to re-run. Follow with `lefthook install`.

ddl init --yes --gates
# Full bootstrap with gates wiring — the one-shot setup

Init cascade semantics

Tool inits run in a prerequisite order (openspec before ah), with the .ddl/bin directory on the PATH so freshly downloaded binaries can be initialized, and tools without an init command are skipped silently.

  • A failing tool init fails the run with a resume summary listing the exact command to finish manually (e.g. dont init) or the selective re-run (ddl init --tools dont). No more exit-0 half-configured repos.
  • Successful inits are recorded in .ddl/manifest.json; re-runs skip them (idempotent-until-green) instead of failing on tools that refuse re-initialization.
  • Non-interactive mode (--yes/--json) passes prompt-free flags to tools with wizards (e.g. pretender init --non-interactive).

ddl install <tool>

Install a single tool by name.

ddl install wai
ddl install dont
ddl install ah
ddl install pretender
ddl install testaruda
ddl install vampiro
ddl install bd
ddl install openspec
ddl install incitaciones
ddl install turu
ddl install specodelic

ddl install, ddl init --tools, and ddl upgrade <tool> accept both the binary name and the crate name, case-insensitive.

Canonical names and aliases

Binary names and crate names don’t always match — and agents repeatedly cargo install the crate expecting the binary, or gh repo view the binary name expecting the repo. The table below lists only the tools whose names mismatch (the rest install by their own name):

binarycraterepository
waiwai-clicharly-vibes/wai
dontdont-clicharly-vibes/dont
ahespectacularcharly-vibes/espectacular
turuwhisper-vibescharly-vibes/whisper
wildwild-vibescharly-vibes/wild
openspec@fission-ai/openspec (npm)fission-ai/openspec
ddl (this tool)dulce-de-lechecharly-vibes/dulce-de-leche

So ddl install espectacular installs ah. Typing ddl, dulce, or dulce-de-leche into ddl install / --tools produces an error naming the canonical repository — ddl manages every tool except itself.

ddl status

Show cross-tool health overview.

ddl status
ddl status --json   # machine-readable output

ddl doctor

Run detailed diagnostics across all tools.

ddl doctor
ddl doctor --fix     # attempt auto-fix
ddl doctor --json    # machine-readable output

ddl version

Show versions of ddl and all managed tools.

ddl version
ddl version --check  # check latest available versions (requires network)

ddl upgrade

Update all tools to latest compatible versions.

ddl upgrade
ddl upgrade wai      # upgrade a single tool

ddl migrate

Move existing configs under .ddl/ (phase-1 symlink farm). To unify disparate per-tool config dirs into one managed place, this is the path: run ddl migrate at the repo root; each tool’s legacy config dir (.wai/, .testaruda/, …) is moved under .ddl/<tool>/ and replaced by a symlink.

ddl migrate
ddl migrate --undo   # restore previous layout

Safety semantics (gh#30):

  • Git-tracked configs are skipped with guidance. Git does not follow symlinks, so replacing a tracked dir would make every tracked file vanish from other clones. ddl migrate detects tracked paths (git ls-files) and leaves them in place, telling you how to untrack first if you really want them under .ddl/.
  • --undo is non-destructive. Each legacy path is restored as a copy of the current .ddl/<tool>/ contents; the .ddl/ backing store is kept, so the undo can never lose tool state and a re-migrate is lossless. The manifest’s migration_state is reset to none.

ddl scope

Show which .ddl/ is active.

ddl scope

ddl feedback <kind>

File a feedback issue against ddl’s own repository (charly-vibes/dulce-de-leche) via gh. The repository URL is compiled into the binary, so this works from any directory — no repo spelunking.

Note: the binary is ddl, but the crate is dulce-de-leche (cargo install dulce-de-leche). Looking for charly-vibes/ddl on GitHub returns 404 — the canonical repository is charly-vibes/dulce-de-leche.

ddl feedback bug                  # kind: bug|feature|question|chore
ddl feedback bug --dry-run        # print issue body + gh command, don't submit
ddl feedback bug --from-last-error  # prefill body from the last failed ddl command
echo "what happened" | ddl feedback bug  # pipe body content via stdin
ddl feedback bug --title "custom title"  # override the derived title

The issue body is pre-filled with environment context automatically: ddl version, OS/arch, shell, gh version, current git remote/branch/dirty state, repo tooling state, and a repro hash. Without network access, the body is saved to a local file so nothing is lost.

Global flags

FlagDescription
-v, -vv, -vvvEnable verbose output (progressive detail)
-q, --quietSuppress output except errors
-y, --yesNon-interactive mode
--jsonOutput as JSON for machine parsing
--humanForce human-readable output in non-TTY contexts
--verboseAlias for -v

Exit codes

CodeMeaning
0Success
1Error (any failure — see stderr for details)

Failures are not distinguished by exit code; the human-readable error and its remediation hint are printed to stderr. Scripts should parse --json output instead of exit codes.