A Python CLI for macOS that installs, manages, and talks to the Draw Things gRPCServerCLI. It can install the server as a LaunchAgent, generate images over gRPC, and browse community model metadata.
This project is alpha (0.x). Expect breaking changes; pin a commit or version if you depend on it.
- Command reference: CLI.md — full flags plus a How to use this doc table at the top.
- Wire format: DRAW-THINGS-GRPC-API.md (messages and streaming), PROTOBUF.md (FlatBuffer config and protos).
- Documentation map: docs/README.md.
- Product docs (Draw Things): drawthings.ai/docs.
- Python 3.12+ and
uv. - macOS only if you use
dts-utils server …to install or managegRPCServerCLIwith LaunchAgent.generate,reflect, anddts-utils webrun anywhere Python can reach the server. flatconPATHwhen you pass JSON configuration (conversion uses the bundledconfig.fbs).
git clone https://github.com/funkatron/dts-utils.git
cd dts-utils
uv sync
uv run dts-utils --helpThree steps to a generated PNG on a fresh Mac: install the server, confirm it is listening, then run prompt-first shorthand (quotes keep multi-word prompts as one argument):
uv run dts-utils server install
uv run dts-utils server check
uv run dts-utils "a beautiful sunset over mountains"Example output below is the repo’s sample PNG (docs/assets/sample-output.png, 768×1024), produced with:
uv run dts-utils "an incredibly detailed mech from Mechwarrior, Depth of field, extreme zoom, tilt-shift, extreme angles, dramatic perspective"Your runs will vary with model, default.json, and prompt.
What each step does:
server installinstalls the LaunchAgent and startsgRPCServerCLIwith default settings.server checkprobes the local port to confirm a listener. (server testis the same probe with a different name.)- Shorthand runs
generatewith--trust-server-cert,--open, and the configuration described under Shorthand profile (default).- First run may create
default.jsonin the saved-config directory and print a hint on stderr if it cannot guess a checkpoint name formodel. - PNGs default to
./output(output/generated.png). Each run gets a millisecond suffix before the extension so files are not overwritten.
- First run may create
To call generate explicitly with a saved profile (for example portrait.json from dts-utils configs path):
uv run dts-utils generate \
--prompt "a beautiful sunset over mountains" \
--configuration portrait \
--trust-server-certSkip server install / server check if the server already runs elsewhere; see Remote or existing servers.
Blank Mac with no checkpoints yet: the quickstart assumes something usable ends up in default.json (often after Draw Things has populated Models). For an explicit walkthrough — install the Draw Things app preset Z Image Turbo 1.0 (Exact), dts-utils, models build, configs scaffold-from-metadata, then generate — see docs/setup-clean-install-z-image-turbo.md.
Optional browser UI (same gRPC server; loopback HTTP only by default):
uv run dts-utils web --open
# second terminal: uv run dts-utils web tail| Goal | Command |
|---|---|
| Run the browser UI | uv run dts-utils web (add --open to launch the browser) |
| Follow web UI logs | uv run dts-utils web tail (second terminal; path printed when web starts) |
See CLI.md — web for bind address, DTS_WEB_TOKEN, and API shape.
dts-utils generate (explicit subcommand) requires a Draw Things configuration via --configuration or --configuration-json. Without one it exits before opening a stream.
--configuration VALUE accepts three forms:
| You pass | Resolution |
|---|---|
A name like portrait (no slashes, not an existing path) |
portrait.json inside the directory printed by dts-utils configs path. |
A .json file path |
Converted to FlatBuffer bytes with flatc and the bundled config.fbs. |
| Any other existing file | Read as raw FlatBuffer bytes; extension may differ from .bin. |
--configuration-json is JSON-only (name or path) and is mutually exclusive with --configuration. Most people use --configuration only.
Saved configs:
uv run dts-utils configs path # print the directory (creates it)
uv run dts-utils configs list # list saved JSON names (no `.json` suffix in the listing)
uv run dts-utils configs scaffold-from-metadata --scan ~/.cache/community-models/models --limit 50 --dry-run # batch starter profiles from cloned community metadata (see CLI.md)Default locations: macOS, Linux, and other Unix-like systems use ~/.config/dts-utils when XDG_CONFIG_HOME is unset ($XDG_CONFIG_HOME/dts-utils otherwise). Windows uses %APPDATA%\dts-utils.
When you run prompt-first shorthand (dts-utils "prompt", optional profile as the second argument, optional flags after that), configuration is chosen in this order:
- Second positional argument, if present (same resolution as
--configuration: saved name, path to.json, or raw FlatBuffer path). DTS_UTILS_DEFAULT_CONFIGURATION, if set and non-empty (name or path).- Otherwise the saved profile
default(default.jsonnext todts-utils configs path).- If
default.jsonis missing butzit.jsonexists there (older installs), the tool renameszit.json→default.jsononce. - If neither exists, the tool creates
default.jsononce: 512×512, typical sampling fields, andmodelchosen from (in order) the first.ckpt/.safetensorsunder your Draw Things models directory orDRAW_THINGS_MODEL_PATH, orDTS_UTILS_DEFAULT_MODEL, or left blank with a short stderr hint to edit the file.
- If
After that, the process calls os.environ.setdefault("DTS_UTILS_DEFAULT_CONFIGURATION", "default"), so an environment value you already exported keeps precedence.
Full rules and examples: CLI.md § Generate shorthand.
| Situation | Flag |
|---|---|
| Localhost, server cert not in system trust | --trust-server-cert (loopback only) |
| Remote or LAN, PEM you trust | --root-cert PATH (often with --host) |
Server installed with --no-tls |
--no-tls on the client |
| Shared secret on the server | --shared-secret SECRET |
| Short remote diagnostic without a PEM | --force-trust-server-cert (accepts any cert; MITM risk) |
Pin the server’s presented certificate:
uv run dts-utils tls path # default PEM destination
uv run dts-utils tls export # fetch and write PEMserver install --export-tls-cert runs the export after a successful local check (not used with --no-tls). Only client-side files change; gRPCServerCLI keystores are not modified.
Commands assume the LaunchAgent layout and use local probes (pgrep / lsof). The server prefix is required so these verbs are not confused with other tools.
| Goal | Command |
|---|---|
| Install with defaults | uv run dts-utils server install |
| Confirm process and port | uv run dts-utils server check (or server test) |
| Follow server logs (macOS) | uv run dts-utils server tail |
| Custom port, secret, or models path | uv run dts-utils server install --port 7860 --shared-secret "…" --model-path /path/to/models |
| Enable model browsing on an existing install | uv run dts-utils server restart --model-browser |
| Stop / start without removing install | uv run dts-utils server stop · uv run dts-utils server start |
| Restart or fully remove | uv run dts-utils server restart · uv run dts-utils server uninstall |
Flag-level detail: CLI.md.
If gRPCServerCLI runs elsewhere, point generate and reflect at the host:
uv run dts-utils generate \
--host gpu.local \
--prompt "a beautiful sunset over mountains" \
--configuration portrait \
--root-cert ./gpu.pemserver check only probes localhost. For reachability and API surface on a remote host, use reflect:
uv run dts-utils reflect --host gpu.local --root-cert ./gpu.pem
uv run dts-utils reflect --host gpu.local --root-cert ./gpu.pem --json| Goal | Command pattern |
|---|---|
| Prompt-first with defaults (local TLS trust, open viewer) | uv run dts-utils "PROMPT" (optional profile and flags; see CLI.md) |
| Saved config | --configuration NAME --trust-server-cert (add --open to open the PNG) |
| Inline JSON path | --configuration path/to/config.json --trust-server-cert |
| Pinned PEM | --root-cert cert.pem (often with --host) |
| Plaintext gRPC | --no-tls |
| Raw FlatBuffer on disk | --configuration /path/to/payload |
--open uses the platform default viewer (open on macOS, xdg-open on Linux, start on Windows).
--output always gets the millisecond suffix on disk; scripts should read stdout (Wrote …) or glob the parent directory for the exact path.
Local index over public Draw Things community-model metadata. No GenerateImage server required.
uv run dts-utils models build # clone/update metadata, build local tables
uv run dts-utils models fetch --dry-run # bundled recipe plan (roadmap: docs/models-fetch-roadmap.md)
uv run dts-utils models search flux
uv run dts-utils models search sdxl anime
uv run dts-utils models search --family Flux --has-hf
uv run dts-utils models show MODEL_ID
uv run dts-utils models reportFilters: --family, --type, --author, --license, --has-source, --has-hf, --has-license, --has-downloads, --has-warnings.
Output paths:
| Path | Contents |
|---|---|
data/drawthings_uncurated_models.json |
Full dataset |
data/drawthings_uncurated_models.csv |
CSV slice |
data/drawthings_models.sqlite |
SQLite database |
data/report.html |
HTML report |
.cache/community-models/ |
Cloned drawthingsai/community-models |
.cache/huggingface/ |
Hugging Face API cache |
build reads uncurated_models.txt, SHA manifests, and metadata.json trees. Bad rows surface as warnings rather than failing the build.
| Symptom | Where to look |
|---|---|
server check fails |
Wrong port; or use dts-utils server check --no-tls when the server runs with --no-tls. Otherwise dts-utils server tail, plist, server restart, or server stop then server start |
TLS error against localhost |
Add --trust-server-cert for loopback on generate. See TLS |
generate exits before streaming |
For explicit generate, pass --configuration / --configuration-json. For shorthand, see Shorthand profile (default). Wrong or missing model in JSON often fails at the server |
reflect returns UNIMPLEMENTED |
Draw Things gRPCServerCLI often omits gRPC reflection; generation can still work |
| PNG looks like noise | Usually wrong model in default.json (or your chosen profile) — basename must exist in the server model directory — or a bad tensor decode. Open the JSON from dts-utils configs path and fix model / width / height. Trim accidental spaces in quoted prompts |
| “Cannot resolve … config” | dts-utils configs path and dts-utils configs list; save the file there or pass an absolute path |
src/
└── dts_utils/
├── installer/ # LaunchAgent-backed install lifecycle (macOS)
├── cli_router.py # Top-level dispatch (`dts-utils`) and prompt-first shorthand
├── configs.py # Saved JSON configs and default implicit profile materialization
├── generate.py # Prompt → gRPC GenerateImage → PNG
├── tls_export.py # Pin/export server PEM (`dts-utils tls`)
├── grpc/ # Channels, reflection, stubs, protobuf copies (`grpc/utils.py`, …)
├── model_index/ # Community metadata index (`dts-utils models`)
└── web/ # Loopback Starlette UI (`dts-utils web`)
Per-flag behavior: CLI.md.
| Doc | Covers |
|---|---|
| CLI.md | Subcommands, shorthand, environment variables, flags |
| docs/README.md | Where to read what (operator map) |
| DRAW-THINGS-GRPC-API.md | ImageGenerationService, ImageGenerationRequest, streaming |
| PROTOBUF.md | Proto + FlatBuffer GenerationConfiguration, test notes |
| tests/README.md | Pytest and manual release smoke (live server) |
| AGENTS.md | Conventions for contributors and automation |
| Draw Things docs | Product documentation outside this repo |
uv sync --dev
uv run pytestOptional integration tests may skip without a local gRPC server; maintainer notes: PROTOBUF.md § gRPC integration tests and tests/README.md.
MIT — see LICENSE.
Pull requests welcome. Pair behavioral changes with pytest updates in the same change when practical.
Contributors and automation: see AGENTS.md and the documentation map.
Releases: when tagging a version, follow CHANGELOG.md § Maintainer release checklist — record the draw-things-community gRPCServerCLI release tag you smoke-tested, or state that you did not run a live server.