nomadctl 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. nomadctl-0.2.0/LICENSE +21 -0
  2. nomadctl-0.2.0/PKG-INFO +268 -0
  3. nomadctl-0.2.0/README.md +236 -0
  4. nomadctl-0.2.0/pyproject.toml +187 -0
  5. nomadctl-0.2.0/src/nd/__init__.py +7 -0
  6. nomadctl-0.2.0/src/nd/binary/__init__.py +10 -0
  7. nomadctl-0.2.0/src/nd/binary/env.py +43 -0
  8. nomadctl-0.2.0/src/nd/binary/runner.py +192 -0
  9. nomadctl-0.2.0/src/nd/cli.py +97 -0
  10. nomadctl-0.2.0/src/nd/commands/__init__.py +1 -0
  11. nomadctl-0.2.0/src/nd/commands/_common.py +101 -0
  12. nomadctl-0.2.0/src/nd/commands/clean.py +50 -0
  13. nomadctl-0.2.0/src/nd/commands/exec.py +67 -0
  14. nomadctl-0.2.0/src/nd/commands/list.py +120 -0
  15. nomadctl-0.2.0/src/nd/commands/logs.py +76 -0
  16. nomadctl-0.2.0/src/nd/commands/plan.py +103 -0
  17. nomadctl-0.2.0/src/nd/commands/run.py +372 -0
  18. nomadctl-0.2.0/src/nd/commands/status/__init__.py +29 -0
  19. nomadctl-0.2.0/src/nd/commands/status/command.py +102 -0
  20. nomadctl-0.2.0/src/nd/commands/status/render.py +172 -0
  21. nomadctl-0.2.0/src/nd/commands/status/report.py +339 -0
  22. nomadctl-0.2.0/src/nd/commands/stop.py +412 -0
  23. nomadctl-0.2.0/src/nd/commands/volume/__init__.py +25 -0
  24. nomadctl-0.2.0/src/nd/commands/volume/command.py +216 -0
  25. nomadctl-0.2.0/src/nd/commands/volume/render.py +132 -0
  26. nomadctl-0.2.0/src/nd/commands/volume/report.py +146 -0
  27. nomadctl-0.2.0/src/nd/constants.py +43 -0
  28. nomadctl-0.2.0/src/nd/jobfiles.py +125 -0
  29. nomadctl-0.2.0/src/nd/nomad/__init__.py +29 -0
  30. nomadctl-0.2.0/src/nd/nomad/client.py +51 -0
  31. nomadctl-0.2.0/src/nd/nomad/config.py +156 -0
  32. nomadctl-0.2.0/src/nd/nomad/errors.py +52 -0
  33. nomadctl-0.2.0/src/nd/nomad/models/__init__.py +1 -0
  34. nomadctl-0.2.0/src/nd/nomad/models/agent.py +26 -0
  35. nomadctl-0.2.0/src/nd/nomad/models/allocation.py +37 -0
  36. nomadctl-0.2.0/src/nd/nomad/models/deployment.py +40 -0
  37. nomadctl-0.2.0/src/nd/nomad/models/evaluation.py +21 -0
  38. nomadctl-0.2.0/src/nd/nomad/models/job.py +51 -0
  39. nomadctl-0.2.0/src/nd/nomad/models/node.py +41 -0
  40. nomadctl-0.2.0/src/nd/nomad/models/volume.py +28 -0
  41. nomadctl-0.2.0/src/nd/nomad/resources/__init__.py +1 -0
  42. nomadctl-0.2.0/src/nd/nomad/resources/agent.py +25 -0
  43. nomadctl-0.2.0/src/nd/nomad/resources/allocations.py +24 -0
  44. nomadctl-0.2.0/src/nd/nomad/resources/base.py +45 -0
  45. nomadctl-0.2.0/src/nd/nomad/resources/deployments.py +28 -0
  46. nomadctl-0.2.0/src/nd/nomad/resources/evaluations.py +19 -0
  47. nomadctl-0.2.0/src/nd/nomad/resources/jobs.py +70 -0
  48. nomadctl-0.2.0/src/nd/nomad/resources/nodes.py +24 -0
  49. nomadctl-0.2.0/src/nd/nomad/resources/status.py +14 -0
  50. nomadctl-0.2.0/src/nd/nomad/resources/system.py +25 -0
  51. nomadctl-0.2.0/src/nd/nomad/resources/volumes.py +42 -0
  52. nomadctl-0.2.0/src/nd/nomad/transport.py +141 -0
  53. nomadctl-0.2.0/src/nd/targets/__init__.py +32 -0
  54. nomadctl-0.2.0/src/nd/targets/alloc_target.py +166 -0
  55. nomadctl-0.2.0/src/nd/targets/selection.py +91 -0
  56. nomadctl-0.2.0/src/nd/ui/__init__.py +1 -0
  57. nomadctl-0.2.0/src/nd/ui/alloc_rows.py +93 -0
  58. nomadctl-0.2.0/src/nd/ui/duration.py +44 -0
  59. nomadctl-0.2.0/src/nd/ui/links.py +22 -0
  60. nomadctl-0.2.0/src/nd/ui/live_panel.py +199 -0
  61. nomadctl-0.2.0/src/nd/ui/panels.py +31 -0
  62. nomadctl-0.2.0/src/nd/ui/prompts.py +46 -0
  63. nomadctl-0.2.0/src/nd/ui/styles.py +52 -0
  64. nomadctl-0.2.0/src/nd/volumefiles.py +143 -0
nomadctl-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nathaniel Landau
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,268 @@
1
+ Metadata-Version: 2.4
2
+ Name: nomadctl
3
+ Version: 0.2.0
4
+ Summary: A friendly command-line tool for managing a HashiCorp Nomad homelab cluster.
5
+ Keywords: cli,devops,hashicorp,homelab,nomad,orchestration
6
+ Author: Nathaniel Landau
7
+ Author-email: Nathaniel Landau <github@natelandau.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: System Administrators
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: System :: Systems Administration
18
+ Classifier: Topic :: Utilities
19
+ Classifier: Typing :: Typed
20
+ Requires-Dist: httpx2>=2.4.0,<3.0.0
21
+ Requires-Dist: lark>=1.3.1,<2.0.0
22
+ Requires-Dist: msgspec>=0.21.1
23
+ Requires-Dist: nclutils>=3.4.1,<4.0.0
24
+ Requires-Dist: python-hcl2>=8.1.2,<9.0.0
25
+ Requires-Dist: rich>=15.0.0
26
+ Requires-Dist: typer>=0.26.7
27
+ Requires-Python: >=3.13, <3.15
28
+ Project-URL: Homepage, https://github.com/natelandau/nd
29
+ Project-URL: Issues, https://github.com/natelandau/nd/issues
30
+ Project-URL: Repository, https://github.com/natelandau/nd
31
+ Description-Content-Type: text/markdown
32
+
33
+ [![Automated Tests](https://github.com/natelandau/nd/actions/workflows/automated-tests.yml/badge.svg)](https://github.com/natelandau/nd/actions/workflows/automated-tests.yml) [![codecov](https://codecov.io/gh/natelandau/nd/graph/badge.svg?token=HpyhUwExqh)](https://codecov.io/gh/natelandau/nd)
34
+
35
+ # nd
36
+
37
+ A friendly command-line tool for managing a Nomad cluster.
38
+
39
+ `nd` wraps the Nomad HTTP API and the local `nomad` binary behind a small set of
40
+ task-focused commands. Instead of stitching together multiple nomad commands, you
41
+ get easy to remember commands that marry your on-disk job and volume files and the
42
+ live cluster. No more no more hunting for an allocation ID or task name, just use
43
+ your easy to remember job and volume names and the cli does the rest.
44
+
45
+ ## Features
46
+
47
+ - A one-screen cluster dashboard covering nodes, jobs, allocations, deployments,
48
+ evaluations, and host volumes.
49
+ - Deploy and stop commands that watch the rollout or drain live and report a clear
50
+ success or failure at the end.
51
+ - Job-file aware commands that discover and work with your local `.hcl` and `.nomad` specs
52
+ - Interactive shell and log streaming for any task, with a prompt to pick the job,
53
+ allocation, and task when the choice is ambiguous.
54
+ - Dynamic host volume management: register, delete, and list host volumes across
55
+ every eligible node.
56
+ - Standard `NOMAD_*` environment variables work out of the box, with an optional
57
+ config file for anything you would rather not retype.
58
+
59
+ ## Requirements
60
+
61
+ - Python 3.13 or 3.14.
62
+ - A reachable Nomad cluster.
63
+ - The `nomad` binary on your `PATH`. The `plan`, `run`, `exec`, and `logs` commands
64
+ shell out to it, because the HTTP API cannot parse HCL2 job files and does not own
65
+ the interactive exec protocol. The other commands use the API only.
66
+
67
+ ## Installation
68
+
69
+ The tool is published to PyPI as `nomadctl`. The installed command is `nd`.
70
+
71
+ Install it as an isolated CLI with [uv](https://docs.astral.sh/uv/):
72
+
73
+ ```bash
74
+ uv tool install nomadctl
75
+ ```
76
+
77
+ Or with `pipx`:
78
+
79
+ ```bash
80
+ pipx install nomadctl
81
+ ```
82
+
83
+ Confirm the install:
84
+
85
+ ```bash
86
+ nd --version
87
+ ```
88
+
89
+ ## Configuration
90
+
91
+ `nd` reads the standard Nomad environment variables first, then overrides them with
92
+ an optional config file. If you already run `nomad` from your shell, `nd` targets
93
+ the same cluster with no extra setup.
94
+
95
+ ### Environment variables
96
+
97
+ | Variable | Purpose | Default |
98
+ | ----------------------- | ---------------------------- | -------------------------- |
99
+ | `NOMAD_ADDR` | Cluster API address | `http://127.0.0.1:4646` |
100
+ | `NOMAD_TOKEN` | ACL token | none |
101
+ | `NOMAD_NAMESPACE` | Default namespace | none |
102
+ | `NOMAD_REGION` | Default region | none |
103
+ | `NOMAD_CACERT` | Path to a CA certificate | none |
104
+ | `NOMAD_CLIENT_CERT` | Path to a client certificate | none |
105
+ | `NOMAD_CLIENT_KEY` | Path to a client key | none |
106
+ | `NOMAD_TLS_SERVER_NAME` | TLS server name override | none |
107
+ | `NOMAD_UI_URL` | Base URL for web UI links | falls back to `NOMAD_ADDR` |
108
+
109
+ ### Config file
110
+
111
+ For settings you do not want to export every session, create
112
+ `~/.config/nd/config.toml` (or `$XDG_CONFIG_HOME/nd/config.toml`). Values here
113
+ override the environment.
114
+
115
+ ```toml
116
+ [nomad]
117
+ address = "https://nomad.example.com:4646"
118
+ token = "your-acl-token"
119
+ ui_url = "https://nomad.example.com"
120
+
121
+ # Directories nd searches for .hcl and .nomad job files.
122
+ [jobs]
123
+ directories = ["~/homelab/jobs"]
124
+
125
+ # Directories nd searches for host volume spec files.
126
+ [volumes]
127
+ directories = ["~/homelab/volumes"]
128
+ ```
129
+
130
+ The `[jobs]` and `[volumes]` directory lists power the file-aware commands. Without
131
+ them, `list`, `plan`, `run`, and the `volume` commands have nothing to discover.
132
+
133
+ ## Quick start
134
+
135
+ Point `nd` at your cluster, then look at it:
136
+
137
+ ```bash
138
+ export NOMAD_ADDR="https://nomad.example.com:4646"
139
+ export NOMAD_TOKEN="your-acl-token"
140
+
141
+ nd
142
+ ```
143
+
144
+ Add a job directory to your config file, then list your specs against the live
145
+ cluster:
146
+
147
+ ```bash
148
+ nd list
149
+ ```
150
+
151
+ Deploy a job that is not yet running and watch it roll out:
152
+
153
+ ```bash
154
+ nd run web
155
+ ```
156
+
157
+ Tail its logs, then open a shell inside it:
158
+
159
+ ```bash
160
+ nd logs web
161
+ nd exec web
162
+ ```
163
+
164
+ ## Commands
165
+
166
+ Run `nd --help`, or `nd <command> --help`, for the full option list at any time.
167
+
168
+ | Command | What it does |
169
+ | --------------------------- | --------------------------------------------------------------------------------- |
170
+ | `nd status` | Show an at-a-glance overview of the cluster. Also runs when you type `nd` alone. |
171
+ | `nd list` | List discovered job files and whether each is running, dead, or not deployed. |
172
+ | `nd plan [JOB]` | Preview the changes one or more job files would apply, including to running jobs. |
173
+ | `nd run [JOB]` | Deploy not-yet-running job files and watch the rollout. |
174
+ | `nd stop [JOB]` | Stop, and optionally purge, running jobs and watch them drain. |
175
+ | `nd logs [JOB]` | Stream, tail, or export a task's logs. |
176
+ | `nd exec [JOB]` | Open an interactive shell inside a running task. |
177
+ | `nd clean` | Force garbage collection and reconcile job summaries. |
178
+ | `nd volume register [NAME]` | Register host volumes on every eligible node. |
179
+ | `nd volume delete [NAME]` | Delete registered host volumes matching the selected specs. |
180
+ | `nd volume list [NAME]` | List host volume specs and where each is registered. |
181
+
182
+ ### Targeting jobs by name
183
+
184
+ Commands that take a `JOB` or `NAME` argument match by case-insensitive name prefix.
185
+ A single match runs straight away; several matches open a prompt. Omit the argument
186
+ to pick from a list of every candidate.
187
+
188
+ ```bash
189
+ nd run web # runs the one job whose name starts with "web"
190
+ nd stop # prompts you to choose from all running jobs
191
+ ```
192
+
193
+ ### Previewing before you act
194
+
195
+ Lifecycle commands accept `--dry-run` (`-n`) to report their targets without
196
+ touching the cluster:
197
+
198
+ ```bash
199
+ nd run --dry-run
200
+ nd stop web --dry-run
201
+ nd volume register --dry-run
202
+ ```
203
+
204
+ For `nd run`, a dry run still validates each job file locally, so it catches a
205
+ broken spec without registering anything.
206
+
207
+ ### Deploying jobs
208
+
209
+ `nd run` only offers jobs that are not already running. Each selected file is
210
+ validated and registered, then watched live until its deployment or allocations
211
+ settle. Use `--detach` to register and return without watching the rollout.
212
+
213
+ ```bash
214
+ nd run # choose from every deployable job
215
+ nd run web # deploy the job whose name starts with "web"
216
+ nd run web --detach # register and return immediately
217
+ ```
218
+
219
+ ### Working with logs
220
+
221
+ `nd logs` streams both stdout and stderr live until you press Ctrl-C. Narrow or
222
+ redirect the output with flags:
223
+
224
+ ```bash
225
+ nd logs web # follow stdout and stderr
226
+ nd logs web --stderr # follow stderr only
227
+ nd logs web --tail 100 # print the last 100 lines, no follow
228
+ nd logs web --export run.log # write the current logs to a file
229
+ ```
230
+
231
+ ### Stopping jobs
232
+
233
+ `nd stop` confirms before it acts unless you pass `--force`. Use `--purge` to
234
+ garbage-collect the job afterward, `--detach` to return without watching the drain,
235
+ and `--no-shutdown-delay` to skip the configured shutdown delays for an immediate
236
+ teardown.
237
+
238
+ ```bash
239
+ nd stop web # confirm, stop, and watch it drain
240
+ nd stop web --purge --force # purge without a prompt
241
+ nd stop web --detach # request the stop and return immediately
242
+ ```
243
+
244
+ ### Verbosity
245
+
246
+ Add `-v` for debug output or `-vv` to trace each API request with timings. The flag
247
+ works before or after the subcommand.
248
+
249
+ ```bash
250
+ nd status -v
251
+ nd -vv run web
252
+ ```
253
+
254
+ ## Development
255
+
256
+ The project uses [uv](https://docs.astral.sh/uv/) for dependency management and
257
+ [duty](https://pawamoy.github.io/duty/) as a task runner.
258
+
259
+ ```bash
260
+ uv sync # install dependencies
261
+ uv run nd --help # run the CLI from source
262
+ uv run duty lint # run ruff, ty, typos, and prek
263
+ uv run duty test # run the test suite with coverage
264
+ ```
265
+
266
+ ## License
267
+
268
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,236 @@
1
+ [![Automated Tests](https://github.com/natelandau/nd/actions/workflows/automated-tests.yml/badge.svg)](https://github.com/natelandau/nd/actions/workflows/automated-tests.yml) [![codecov](https://codecov.io/gh/natelandau/nd/graph/badge.svg?token=HpyhUwExqh)](https://codecov.io/gh/natelandau/nd)
2
+
3
+ # nd
4
+
5
+ A friendly command-line tool for managing a Nomad cluster.
6
+
7
+ `nd` wraps the Nomad HTTP API and the local `nomad` binary behind a small set of
8
+ task-focused commands. Instead of stitching together multiple nomad commands, you
9
+ get easy to remember commands that marry your on-disk job and volume files and the
10
+ live cluster. No more no more hunting for an allocation ID or task name, just use
11
+ your easy to remember job and volume names and the cli does the rest.
12
+
13
+ ## Features
14
+
15
+ - A one-screen cluster dashboard covering nodes, jobs, allocations, deployments,
16
+ evaluations, and host volumes.
17
+ - Deploy and stop commands that watch the rollout or drain live and report a clear
18
+ success or failure at the end.
19
+ - Job-file aware commands that discover and work with your local `.hcl` and `.nomad` specs
20
+ - Interactive shell and log streaming for any task, with a prompt to pick the job,
21
+ allocation, and task when the choice is ambiguous.
22
+ - Dynamic host volume management: register, delete, and list host volumes across
23
+ every eligible node.
24
+ - Standard `NOMAD_*` environment variables work out of the box, with an optional
25
+ config file for anything you would rather not retype.
26
+
27
+ ## Requirements
28
+
29
+ - Python 3.13 or 3.14.
30
+ - A reachable Nomad cluster.
31
+ - The `nomad` binary on your `PATH`. The `plan`, `run`, `exec`, and `logs` commands
32
+ shell out to it, because the HTTP API cannot parse HCL2 job files and does not own
33
+ the interactive exec protocol. The other commands use the API only.
34
+
35
+ ## Installation
36
+
37
+ The tool is published to PyPI as `nomadctl`. The installed command is `nd`.
38
+
39
+ Install it as an isolated CLI with [uv](https://docs.astral.sh/uv/):
40
+
41
+ ```bash
42
+ uv tool install nomadctl
43
+ ```
44
+
45
+ Or with `pipx`:
46
+
47
+ ```bash
48
+ pipx install nomadctl
49
+ ```
50
+
51
+ Confirm the install:
52
+
53
+ ```bash
54
+ nd --version
55
+ ```
56
+
57
+ ## Configuration
58
+
59
+ `nd` reads the standard Nomad environment variables first, then overrides them with
60
+ an optional config file. If you already run `nomad` from your shell, `nd` targets
61
+ the same cluster with no extra setup.
62
+
63
+ ### Environment variables
64
+
65
+ | Variable | Purpose | Default |
66
+ | ----------------------- | ---------------------------- | -------------------------- |
67
+ | `NOMAD_ADDR` | Cluster API address | `http://127.0.0.1:4646` |
68
+ | `NOMAD_TOKEN` | ACL token | none |
69
+ | `NOMAD_NAMESPACE` | Default namespace | none |
70
+ | `NOMAD_REGION` | Default region | none |
71
+ | `NOMAD_CACERT` | Path to a CA certificate | none |
72
+ | `NOMAD_CLIENT_CERT` | Path to a client certificate | none |
73
+ | `NOMAD_CLIENT_KEY` | Path to a client key | none |
74
+ | `NOMAD_TLS_SERVER_NAME` | TLS server name override | none |
75
+ | `NOMAD_UI_URL` | Base URL for web UI links | falls back to `NOMAD_ADDR` |
76
+
77
+ ### Config file
78
+
79
+ For settings you do not want to export every session, create
80
+ `~/.config/nd/config.toml` (or `$XDG_CONFIG_HOME/nd/config.toml`). Values here
81
+ override the environment.
82
+
83
+ ```toml
84
+ [nomad]
85
+ address = "https://nomad.example.com:4646"
86
+ token = "your-acl-token"
87
+ ui_url = "https://nomad.example.com"
88
+
89
+ # Directories nd searches for .hcl and .nomad job files.
90
+ [jobs]
91
+ directories = ["~/homelab/jobs"]
92
+
93
+ # Directories nd searches for host volume spec files.
94
+ [volumes]
95
+ directories = ["~/homelab/volumes"]
96
+ ```
97
+
98
+ The `[jobs]` and `[volumes]` directory lists power the file-aware commands. Without
99
+ them, `list`, `plan`, `run`, and the `volume` commands have nothing to discover.
100
+
101
+ ## Quick start
102
+
103
+ Point `nd` at your cluster, then look at it:
104
+
105
+ ```bash
106
+ export NOMAD_ADDR="https://nomad.example.com:4646"
107
+ export NOMAD_TOKEN="your-acl-token"
108
+
109
+ nd
110
+ ```
111
+
112
+ Add a job directory to your config file, then list your specs against the live
113
+ cluster:
114
+
115
+ ```bash
116
+ nd list
117
+ ```
118
+
119
+ Deploy a job that is not yet running and watch it roll out:
120
+
121
+ ```bash
122
+ nd run web
123
+ ```
124
+
125
+ Tail its logs, then open a shell inside it:
126
+
127
+ ```bash
128
+ nd logs web
129
+ nd exec web
130
+ ```
131
+
132
+ ## Commands
133
+
134
+ Run `nd --help`, or `nd <command> --help`, for the full option list at any time.
135
+
136
+ | Command | What it does |
137
+ | --------------------------- | --------------------------------------------------------------------------------- |
138
+ | `nd status` | Show an at-a-glance overview of the cluster. Also runs when you type `nd` alone. |
139
+ | `nd list` | List discovered job files and whether each is running, dead, or not deployed. |
140
+ | `nd plan [JOB]` | Preview the changes one or more job files would apply, including to running jobs. |
141
+ | `nd run [JOB]` | Deploy not-yet-running job files and watch the rollout. |
142
+ | `nd stop [JOB]` | Stop, and optionally purge, running jobs and watch them drain. |
143
+ | `nd logs [JOB]` | Stream, tail, or export a task's logs. |
144
+ | `nd exec [JOB]` | Open an interactive shell inside a running task. |
145
+ | `nd clean` | Force garbage collection and reconcile job summaries. |
146
+ | `nd volume register [NAME]` | Register host volumes on every eligible node. |
147
+ | `nd volume delete [NAME]` | Delete registered host volumes matching the selected specs. |
148
+ | `nd volume list [NAME]` | List host volume specs and where each is registered. |
149
+
150
+ ### Targeting jobs by name
151
+
152
+ Commands that take a `JOB` or `NAME` argument match by case-insensitive name prefix.
153
+ A single match runs straight away; several matches open a prompt. Omit the argument
154
+ to pick from a list of every candidate.
155
+
156
+ ```bash
157
+ nd run web # runs the one job whose name starts with "web"
158
+ nd stop # prompts you to choose from all running jobs
159
+ ```
160
+
161
+ ### Previewing before you act
162
+
163
+ Lifecycle commands accept `--dry-run` (`-n`) to report their targets without
164
+ touching the cluster:
165
+
166
+ ```bash
167
+ nd run --dry-run
168
+ nd stop web --dry-run
169
+ nd volume register --dry-run
170
+ ```
171
+
172
+ For `nd run`, a dry run still validates each job file locally, so it catches a
173
+ broken spec without registering anything.
174
+
175
+ ### Deploying jobs
176
+
177
+ `nd run` only offers jobs that are not already running. Each selected file is
178
+ validated and registered, then watched live until its deployment or allocations
179
+ settle. Use `--detach` to register and return without watching the rollout.
180
+
181
+ ```bash
182
+ nd run # choose from every deployable job
183
+ nd run web # deploy the job whose name starts with "web"
184
+ nd run web --detach # register and return immediately
185
+ ```
186
+
187
+ ### Working with logs
188
+
189
+ `nd logs` streams both stdout and stderr live until you press Ctrl-C. Narrow or
190
+ redirect the output with flags:
191
+
192
+ ```bash
193
+ nd logs web # follow stdout and stderr
194
+ nd logs web --stderr # follow stderr only
195
+ nd logs web --tail 100 # print the last 100 lines, no follow
196
+ nd logs web --export run.log # write the current logs to a file
197
+ ```
198
+
199
+ ### Stopping jobs
200
+
201
+ `nd stop` confirms before it acts unless you pass `--force`. Use `--purge` to
202
+ garbage-collect the job afterward, `--detach` to return without watching the drain,
203
+ and `--no-shutdown-delay` to skip the configured shutdown delays for an immediate
204
+ teardown.
205
+
206
+ ```bash
207
+ nd stop web # confirm, stop, and watch it drain
208
+ nd stop web --purge --force # purge without a prompt
209
+ nd stop web --detach # request the stop and return immediately
210
+ ```
211
+
212
+ ### Verbosity
213
+
214
+ Add `-v` for debug output or `-vv` to trace each API request with timings. The flag
215
+ works before or after the subcommand.
216
+
217
+ ```bash
218
+ nd status -v
219
+ nd -vv run web
220
+ ```
221
+
222
+ ## Development
223
+
224
+ The project uses [uv](https://docs.astral.sh/uv/) for dependency management and
225
+ [duty](https://pawamoy.github.io/duty/) as a task runner.
226
+
227
+ ```bash
228
+ uv sync # install dependencies
229
+ uv run nd --help # run the CLI from source
230
+ uv run duty lint # run ruff, ty, typos, and prek
231
+ uv run duty test # run the test suite with coverage
232
+ ```
233
+
234
+ ## License
235
+
236
+ MIT. See [LICENSE](LICENSE).