Important
Not ctrld: that daemon runs your DNS. cdctl manages your account.
An independent project, not affiliated with Control D.
$ cdctl rule create ads.example.com trackers.example.net --action block
┌──────────────────────┬────────┬─────┬─────────┬────────┐
│ HOSTNAME ┆ ACTION ┆ VIA ┆ ENABLED ┆ FOLDER │
╞══════════════════════╪════════╪═════╪═════════╪════════╡
│ ads.example.com ┆ block ┆ - ┆ true ┆ - │
│ trackers.example.net ┆ block ┆ - ┆ true ┆ - │
└──────────────────────┴────────┴─────┴─────────┴────────┘
$ cdctl rule create tv.example.com --action spoof --via 192.0.2.10
┌────────────────┬────────┬────────────┬─────────┬────────┐
│ HOSTNAME ┆ ACTION ┆ VIA ┆ ENABLED ┆ FOLDER │
╞════════════════╪════════╪════════════╪═════════╪════════╡
│ tv.example.com ┆ spoof ┆ 192.0.2.10 ┆ true ┆ - │
└────────────────┴────────┴────────────┴─────────┴────────┘
$ cdctl rule list --fields hostname,action
[
{
"hostname": "ads.example.com",
"action": "block"
},
{
"hostname": "trackers.example.net",
"action": "block"
},
{
"hostname": "tv.example.com",
"action": "spoof"
}
]Usage: cdctl [OPTIONS] <COMMAND>
Commands:
auth Authenticate cdctl with an API token
profile Inspect the account's profiles
rule Manage a profile's DNS rules
folder Manage a profile's rule folders (API: groups)
config Read and write cdctl's own configuration
api Raw request against the API origin (escape hatch, GET by default)
completions Shell completion script
reference The full command surface as one Markdown document
The account resources and what you can do to each:
| Resource | list | get | create | update | delete |
|---|---|---|---|---|---|
| profile | ✅ | ✅ | |||
| rule | ✅ | ✅ | ✅ | ✅ | |
| folder | ✅ | ✅ | ✅ | ✅ |
Empty cells aren't shipped yet — see the roadmap.
- 🔍 The API can report success for a change it never made, so
cdctlreads every write back and checks it landed. - 🛡️
--dry-runon every write, confirmation on deletes, and errors that say if a retry is safe. - 🤖 Scripts and agents get
--json, data-only stdout, and stable error codes. - 🚦 Exit codes are a contract: 8 means retry, nothing else does.
- 🔑 The token is never passed on the command line, lives in a file only you can read, and is hidden from
--debugoutput. - 📦 One static binary, with completions and man pages.
- 🚪
cdctl apireaches the whole documented API through the same auth, retries, and error handling. - 👤 Personal accounts, with orgs addable later and no breaking changes.
The package is controld-cli; the binary is cdctl.
| Channel | Platforms | Command |
|---|---|---|
| Homebrew | macOS | brew install joaodrp/tap/cdctl |
| Prebuilt archive | macOS, Linux, Windows | from Releases, put cdctl on PATH |
| Cargo | any | cargo install controld-cli |
Archives cover aarch64 and x86_64, Linux in both gnu and musl, and ship completions and man
pages. cdctl completions --help generates one for any shell.
Installer scripts (no upgrade path, so re-run one to update):
# macOS and Linux
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/joaodrp/controld-cli/releases/latest/download/controld-cli-installer.sh | sh
# Windows
powershell -c "irm https://github.com/joaodrp/controld-cli/releases/latest/download/controld-cli-installer.ps1 | iex"Swap latest/download for download/<tag> to pin a version.
Removing the binary leaves the config file, which holds your token if you ran auth login.
cdctl config path prints where it is.
Create an API token in the Control D dashboard, store it, and check it reaches the API:
cdctl auth login --token-stdin # paste the token at the prompt, input stays hidden
cdctl auth statusMost commands operate on one profile. Set a default once instead of passing --profile every
time:
cdctl profile list
cdctl config set default_profile HomeBlock a domain, list the rules, then delete it again. The delete asks you to confirm:
cdctl rule create ads.example.com --action block
cdctl rule list
cdctl rule delete ads.example.comFrom here, every command answers --help, cdctl reference prints the whole surface as one
document, and commands specifies each flag, output column, and exit code.
| Variable | Meaning |
|---|---|
CONTROLD_API_TOKEN |
API token (alternative to cdctl auth login) |
CONTROLD_PROFILE |
Profile to operate on, as --profile |
CONTROLD_OUTPUT |
json makes JSON the default output |
Plain TOML at ~/.config/cdctl/config.toml (%APPDATA%\cdctl\config.toml on Windows, or
wherever $XDG_CONFIG_HOME points):
current_context = "personal"
[contexts.personal]
token = "api.xxxx"
default_profile = "Home"A context is a named token with its own default profile. One is enough unless you have several accounts.
| Key | Meaning | Notes |
|---|---|---|
current_context |
The context in use | Optional, defaults to personal. Set with cdctl config set |
token |
API token for that context | Written by cdctl auth login. Plain text, in a file only you can read |
default_profile |
Profile used when --profile is absent |
Per context. Set with cdctl config set |
cdctl config path prints that path and cdctl config list shows each value with the source it
came from.
When a setting has more than one source, the first one that is set wins:
| Setting | Precedence |
|---|---|
| Profile | --profile > CONTROLD_PROFILE > default_profile |
| Token | CONTROLD_API_TOKEN > token |
| design | Command surface |
| commands | Per-command flags, columns, JSON fields |
| decisions | What was decided, why, what it cost |
| roadmap | What ships next, and its test gates |
| testing | Test layers, fixture policy, live-test isolation |
| reference/ | OpenAPI spec + provenance, live/write verification, error codes |
| AGENTS | Instructions for coding agents |
Bug reports and pull requests are welcome. CONTRIBUTING covers setup, the test gates, and the rules for running anything against the live API.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.