Skip to content

CLI

The dh command-line tool compiles, validates, and watches your pallets. For workspace configuration, see Workspace.

CommandDescription
dhLaunch interactive mode (default if no command given)
dh interactiveLaunch interactive mode (explicit)
dh buildCompile all pallets
dh watchWatch for changes and auto-compile
dh validateValidate pallets without writing output
dh cleanClear the .dh/ cache directory
dh initInitialize a new workspace
dh info <file>Show metadata from a compiled .pallet file
dh helpShow available commands

Running dh with no arguments (or dh interactive) launches an interactive menu where you can choose what to do: build, watch, validate, clean, and more. This is the recommended way to use the CLI for day-to-day work.

FlagShortWorks withDescription
--verbose-vbuild, watch, validate, cleanShow detailed output (Blender logs, file-level progress)
--clean-cbuild, watchClear cache before building
--plainall commandsForce non-interactive, plain-text output (no prompts, no ANSI/colors/spinners)

Example:

Terminal window
dh build --verbose --clean

dh is safe to run unattended — from a script, CI pipeline, or an automation agent — with no terminal attached.

Detection: the CLI automatically treats a run as non-interactive when stdin or stdout is redirected/piped, or when the terminal itself reports no interactive capability. You can also force this mode explicitly with --plain, regardless of how stdio is connected.

Behavior in non-interactive mode:

  • No prompts, ever. Any code path that would normally prompt (e.g. asking for a Blender path) instead fails fast with a plain-text error naming the missing config key and how to fix it, then exits non-zero. For example, if blenderPath is missing from dh-config.jsonc:

    Error: blenderPath is not set. Add "blenderPath": "C:\path\to\blender.exe" to dh-config.jsonc.
  • No live/ANSI rendering. Colors, spinners, and other interactive rendering are suppressed; output is informative plain text.

  • dh watch skips its interactive keypress controls (Space/Enter/R/C/Q) and simply runs until interrupted with Ctrl+C.

  • Exit codes are consistent everywhere: 0 on success, non-zero on any failure (validation errors, missing config, exceptions).

dh watch monitors your Source/ directory and recompiles when files change.

Debounce: waits for changes to settle before compiling (default: 1000ms, configurable via watchDebounceMs).

Manual controls:

KeyAction
Space, Enter, R, CTrigger manual compile
Q, Ctrl+CExit watch mode

dh info displays metadata embedded in compiled .pallet files:

Terminal window
dh info Pallets/io.mltn.avatars.mltn-mayu.pallet

Output:

io.mltn.avatars.mltn-mayu.pallet
╭──────────────────┬─────────────────────────────────────╮
│ Property │ Value │
├──────────────────┼─────────────────────────────────────┤
│ ID │ io.mltn.avatars.mltn-mayu │
│ Name │ mltn Mayu │
│ Version │ 0.0.1 │
│ Author │ mltn │
│ Built │ 2026-02-05 10:30:00 -08:00 │
│ DH Version │ 0.1.0 │
│ Files │ 42 │
│ Size │ 2.4 MB │
│ Uncompressed │ 3.1 MB │
│ Dependencies │ tech.azuki.avatars.mayu ^3.0.0 │
│ Tags │ avatar, character │
╰──────────────────┴─────────────────────────────────────╯

If no file is specified, dh info shows info for all pallets in the build directory.

Building io.mltn.avatars.mltn-mayu...
✓ Parsing definitions
✓ Validating references
✓ Processing textures
✓ Converting models
✓ Bundling assets
✓ Writing output
Build succeeded in 1.2s
Building io.mltn.avatars.mltn-mayu...
✓ Parsing definitions
✗ Validating references
Error in io.mltn.avatars.mltn-mayu/avatar.dh-avatar:12:5
Missing required property 'name' in material definition
10 | "materials": {
11 | "body": {
> 12 | "diffuseTexture": "textures/body.png"
| ^
13 | }
14 | }
Build failed with 1 error

What dh build does under the hood:

  1. Parse — Read all JSONC/.dh-* definition files
  2. Validate — Check schemas, references, types, inheritance chains
  3. Process textures — Channel packing, extraction, and resize from dh.texture definitions and @channel references
  4. Convert models — FBX → GLB via Blender (cached by content hash)
  5. Bundle — LZ4-compress assets into the output pallet
  6. Output — Write compiled .pallet file to Pallets/