python-dmon 0.4.0__tar.gz → 0.5.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.
- python_dmon-0.5.0/LICENSE +21 -0
- python_dmon-0.5.0/PKG-INFO +287 -0
- python_dmon-0.5.0/README.md +266 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/pyproject.toml +8 -6
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/api.py +32 -1
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/cli.py +27 -1
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/config.py +22 -1
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/control.py +164 -16
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/readiness.py +40 -5
- python_dmon-0.5.0/src/dmon/repair.py +303 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/results.py +22 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/supervisor.py +176 -15
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/types.py +108 -5
- python_dmon-0.4.0/PKG-INFO +0 -481
- python_dmon-0.4.0/README.md +0 -462
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/__init__.py +0 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/__main__.py +0 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/constants.py +0 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/inspection.py +0 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/logs.py +0 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/py.typed +0 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/runner.py +0 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/serialization.py +0 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/stack_runner.py +0 -0
- {python_dmon-0.4.0 → python_dmon-0.5.0}/src/dmon/utils.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Atomie CHEN
|
|
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,287 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-dmon
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: A lightweight, cross-platform process manager for background tasks, local service stacks, and partial recovery.
|
|
5
|
+
Keywords: dmon,process manager,daemon,background,supervisor,local development,readiness,service management,coding agents
|
|
6
|
+
Author: Atomie CHEN
|
|
7
|
+
Author-email: Atomie CHEN <atomic_cwh@163.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: colorama>=0.4.6
|
|
11
|
+
Requires-Dist: psutil>=7.1.0
|
|
12
|
+
Requires-Dist: python-dotenv>=1.0.1,<1.1
|
|
13
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
14
|
+
Requires-Dist: termcolor>=2.4.0
|
|
15
|
+
Requires-Dist: tomli>=2.2.1 ; python_full_version < '3.11'
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
|
+
Project-URL: Bug Tracker, https://github.com/atomiechen/dmon/issues
|
|
18
|
+
Project-URL: Changelog, https://github.com/atomiechen/dmon/blob/main/CHANGELOG.md
|
|
19
|
+
Project-URL: Homepage, https://github.com/atomiechen/dmon
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# dmon
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
[](https://github.com/atomiechen/dmon)
|
|
28
|
+
[](https://pypi.org/project/python-dmon/)
|
|
29
|
+
[](https://deepwiki.com/atomiechen/dmon)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
A lightweight, cross-platform process manager for local services and development workflows.
|
|
33
|
+
Run any command as a background *task*, or supervise a stack with readiness checks
|
|
34
|
+
and repair failed members while healthy services keep running. Logging and log
|
|
35
|
+
rotation are built in.
|
|
36
|
+
|
|
37
|
+
For developers and coding agents, dmon records process identities and exposes
|
|
38
|
+
JSON status so later sessions can inspect and reuse existing services.
|
|
39
|
+
See [coding-agent setup](https://github.com/atomiechen/dmon/blob/main/docs/agent-setup.md).
|
|
40
|
+
|
|
41
|
+
Shipped as the CLI tool `dmon`.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- 🖥️ **Cross-platform:** Works on Linux, macOS, and Windows.
|
|
47
|
+
- ⚡ **Lightweight:** No daemon service or container runtime required.
|
|
48
|
+
- 🧩 **Flexible tasks:** Tasks can be configured in `pyproject.toml` or `dmon.yaml`; or run ad-hoc commands directly.
|
|
49
|
+
- 🔗 **Supervised stacks:** Start dependent tasks in order, wait for HTTP, TCP,
|
|
50
|
+
or command readiness, and report runtime degradation.
|
|
51
|
+
- 🌙 **Foreground or detached:** Keep a stack attached for development, or run
|
|
52
|
+
it under a recoverable background supervisor with `dmon stack up -d` and
|
|
53
|
+
`dmon stack down`.
|
|
54
|
+
- ⏱️ **Reusable readiness:** Wait for configured tasks or direct HTTP, TCP, and
|
|
55
|
+
command probes from scripts and deployment workflows.
|
|
56
|
+
- 🪵 **Logging & log rotation:** Keep active log files manageable, with optional archive retention limits.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
## Demos
|
|
60
|
+
|
|
61
|
+
The demos below cover everyday task management and supervised stacks. Both use this `dmon.yaml` and a small [heartbeat program](https://github.com/atomiechen/dmon/blob/main/scripts/recording/service.py):
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
tasks:
|
|
65
|
+
api: [python, -u, service.py, api]
|
|
66
|
+
worker: [python, -u, service.py, worker]
|
|
67
|
+
stacks:
|
|
68
|
+
dev: [api, worker]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Everyday tasks.** Run a command directly with `run` (no configuration needed),
|
|
72
|
+
then use `start`, `status`, and `stop` for a configured task. `exec` runs a
|
|
73
|
+
configured task in the foreground; Ctrl-C ends it. In this clip, `stop --all`
|
|
74
|
+
stops the sole ad-hoc task before the configured API is started.
|
|
75
|
+
|
|
76
|
+

|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
**Keep healthy services running.** Start a stack, deliberately stop its worker,
|
|
80
|
+
and repair that member. The API keeps the same PID and its counter continues;
|
|
81
|
+
`stack down` stops both members. The lower panes show real files and live logs.
|
|
82
|
+
|
|
83
|
+

|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
## Installation
|
|
88
|
+
|
|
89
|
+
`dmon` requires Python 3.8+ and is available as [`python-dmon`](https://pypi.org/project/python-dmon/) on PyPI.
|
|
90
|
+
Managed commands can use any language.
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
pip install python-dmon
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
We recommend installing into an isolated environment, e.g., with `uv` / `pipx`:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
# Install globally with uv tool
|
|
100
|
+
uv tool install python-dmon
|
|
101
|
+
|
|
102
|
+
# Or with pipx
|
|
103
|
+
pipx install python-dmon
|
|
104
|
+
|
|
105
|
+
# Add as a dev dependency in your project
|
|
106
|
+
uv add --dev python-dmon
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
You can also run dmon without installing it permanently:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
# With uvx (uv tool run)
|
|
113
|
+
uvx python-dmon
|
|
114
|
+
|
|
115
|
+
# Or with pipx
|
|
116
|
+
pipx run python-dmon
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
To get the latest features, install from source:
|
|
120
|
+
|
|
121
|
+
```sh
|
|
122
|
+
pip install git+https://github.com/atomiechen/dmon.git
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
For coding agents, see the [setup instructions](https://github.com/atomiechen/dmon/blob/main/docs/agent-setup.md) and the
|
|
126
|
+
[portable skill](https://github.com/atomiechen/dmon/blob/main/skills/dmon/SKILL.md). The skill is installed separately from the CLI.
|
|
127
|
+
|
|
128
|
+
## Getting Started
|
|
129
|
+
|
|
130
|
+
### Prepare Configuration
|
|
131
|
+
|
|
132
|
+
Create a `dmon.yaml` file:
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
tasks:
|
|
136
|
+
app: ["python", "-u", "server.py"] # exec form
|
|
137
|
+
# app: "python -u server.py" # or a shell string
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Without `--config`, dmon searches the current directory and its parents for
|
|
141
|
+
`dmon.yaml`, `dmon.yml`, or `pyproject.toml`. See the
|
|
142
|
+
[configuration reference](https://github.com/atomiechen/dmon/blob/main/docs/configuration.md)
|
|
143
|
+
for TOML, environments, paths, defaults, and log rotation.
|
|
144
|
+
|
|
145
|
+
### Run tasks
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
dmon start app # Start in the background
|
|
149
|
+
dmon stop app # Stop the recorded process tree
|
|
150
|
+
dmon restart app
|
|
151
|
+
dmon status app
|
|
152
|
+
dmon exec app # Run in this terminal; Ctrl-C ends it
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`exec` runs one configured command directly, without registering a managed
|
|
156
|
+
background task. Use `start` to keep it discoverable through `status` and `list`.
|
|
157
|
+
You can pass multiple names to the other task commands. Multi-task `start` is
|
|
158
|
+
best-effort: successful tasks stay running if another fails. For related
|
|
159
|
+
services with ordered startup and rollback, use a stack.
|
|
160
|
+
|
|
161
|
+
### Run a stack
|
|
162
|
+
|
|
163
|
+
```yaml
|
|
164
|
+
tasks:
|
|
165
|
+
api:
|
|
166
|
+
cmd: [python, api.py]
|
|
167
|
+
ready:
|
|
168
|
+
http: http://127.0.0.1:8000/health
|
|
169
|
+
worker:
|
|
170
|
+
cmd: [python, worker.py]
|
|
171
|
+
depends_on: [api]
|
|
172
|
+
stacks:
|
|
173
|
+
dev: [api, worker]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
```sh
|
|
177
|
+
dmon stack up dev # Foreground; Ctrl-C stops the stack
|
|
178
|
+
# Or keep it running under a background supervisor:
|
|
179
|
+
dmon stack up -d dev
|
|
180
|
+
dmon stack status dev
|
|
181
|
+
dmon stack logs --tail 100 dev
|
|
182
|
+
dmon stack repair dev worker --format json # Replace an exited member
|
|
183
|
+
dmon stack down dev
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Stack startup waits for readiness and rolls back tasks it started if startup
|
|
187
|
+
fails. After startup, an exited member degrades the stack while healthy peers
|
|
188
|
+
keep running. `repair` replaces that member through its live supervisor, so
|
|
189
|
+
later `down` includes the replacement. It reuses the supervisor's launch
|
|
190
|
+
configuration and environment; separately running `dmon start worker` does not
|
|
191
|
+
repair stack membership.
|
|
192
|
+
|
|
193
|
+
See [task and stack lifecycle](https://github.com/atomiechen/dmon/blob/main/docs/ownership.md)
|
|
194
|
+
for fail-fast behavior, detached restart, recovery, and ownership limits. Docker
|
|
195
|
+
Compose is still appropriate when container behavior itself must be tested.
|
|
196
|
+
|
|
197
|
+
### Wait for readiness
|
|
198
|
+
|
|
199
|
+
`dmon wait` checks readiness without starting or stopping anything. Configured
|
|
200
|
+
tasks need a `ready` probe and must already be managed by `start` or a stack:
|
|
201
|
+
|
|
202
|
+
```sh
|
|
203
|
+
dmon wait api
|
|
204
|
+
dmon wait api --timeout 60 --interval 0.5
|
|
205
|
+
|
|
206
|
+
# Direct probes need no configuration
|
|
207
|
+
dmon wait --http http://127.0.0.1:8000/health
|
|
208
|
+
dmon wait --tcp 127.0.0.1:5432
|
|
209
|
+
dmon wait --timeout 30 --command -- python healthcheck.py --verbose
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Put dmon options before `--command`; the optional second `--` marks the child
|
|
213
|
+
command. See [readiness configuration](https://github.com/atomiechen/dmon/blob/main/docs/configuration.md#readiness)
|
|
214
|
+
for probe options, listener ownership checks, and wait results.
|
|
215
|
+
|
|
216
|
+
### Run an ad-hoc command
|
|
217
|
+
|
|
218
|
+
```sh
|
|
219
|
+
dmon run --name myserver python -u server.py
|
|
220
|
+
dmon run --name timer -- python -c 'import time; time.sleep(30)'
|
|
221
|
+
dmon run --shell echo "Hello World"
|
|
222
|
+
dmon run --cwd /path/to/script bash myscript.sh
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
No configuration is needed. Without `--name`, dmon uses the fixed name
|
|
226
|
+
`default_run` to prevent duplicate runs.
|
|
227
|
+
|
|
228
|
+
### List recorded tasks and their status
|
|
229
|
+
|
|
230
|
+
```sh
|
|
231
|
+
dmon list
|
|
232
|
+
dmon status app --format json
|
|
233
|
+
dmon list --format json
|
|
234
|
+
dmon stack status dev --format json
|
|
235
|
+
dmon stack list --format json
|
|
236
|
+
dmon wait api --format json
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
JSON is written only to stdout; actionable diagnostics remain on stderr. The
|
|
240
|
+
payload has a top-level `ok` field and a `tasks`, `stacks`, or `waits` array.
|
|
241
|
+
Inspection results contain `name`, `ok`, `error`, and an optional `snapshot`;
|
|
242
|
+
wait results contain the target, outcome, reason, elapsed time, and attempt
|
|
243
|
+
count. Existing exit-code semantics are unchanged. Interactive and streaming
|
|
244
|
+
commands do not offer JSON output.
|
|
245
|
+
|
|
246
|
+
### Python API
|
|
247
|
+
|
|
248
|
+
The same task lifecycle and inspection logic is available without parsing CLI
|
|
249
|
+
output:
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
from dmon import Dmon
|
|
253
|
+
|
|
254
|
+
client = Dmon(config="dmon.yaml")
|
|
255
|
+
started = client.start("app")
|
|
256
|
+
task = client.status("app")
|
|
257
|
+
stacks = client.list_stacks()
|
|
258
|
+
client.stop("app")
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
`client.wait("app", timeout=30)` also checks readiness when `app` has a
|
|
262
|
+
configured `ready` probe. API calls are synchronous and silent.
|
|
263
|
+
`start`, `stop`, and `restart` return an immutable `BatchResult`; `status`
|
|
264
|
+
and `stack_status` return `TaskResult` and `StackResult`. List and wait methods
|
|
265
|
+
return tuples of their corresponding result types. Expected runtime states such
|
|
266
|
+
as missing or exited metadata are results, while invalid configuration raises
|
|
267
|
+
`DmonConfigError`. The initial API intentionally does not start a supervised
|
|
268
|
+
stack or create implicit background threads.
|
|
269
|
+
|
|
270
|
+
## Documentation
|
|
271
|
+
|
|
272
|
+
Start with the [documentation index](https://github.com/atomiechen/dmon/blob/main/docs/README.md):
|
|
273
|
+
|
|
274
|
+
- [Configuration](https://github.com/atomiechen/dmon/blob/main/docs/configuration.md): task selection, YAML/TOML, environments, readiness, and logs.
|
|
275
|
+
- [Task and stack lifecycle](https://github.com/atomiechen/dmon/blob/main/docs/ownership.md): startup, repair, recovery, and process ownership.
|
|
276
|
+
- [Coding-agent setup](https://github.com/atomiechen/dmon/blob/main/docs/agent-setup.md): install the workflow and continue across sessions.
|
|
277
|
+
|
|
278
|
+
## Development
|
|
279
|
+
|
|
280
|
+
See [CONTRIBUTING.md](https://github.com/atomiechen/dmon/blob/main/CONTRIBUTING.md) for architecture, behavioral contracts,
|
|
281
|
+
validation, and the release workflow. Process, signal, log-rotation, and stack
|
|
282
|
+
changes must also pass the reproducible [manual test lab](https://github.com/atomiechen/dmon/blob/main/tests/manual/README.md).
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
## License
|
|
286
|
+
|
|
287
|
+
[dmon](https://github.com/atomiechen/dmon) © 2025 by [Atomie CHEN](https://github.com/atomiechen) is licensed under the [MIT License](https://github.com/atomiechen/dmon/blob/main/LICENSE).
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# dmon
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[](https://github.com/atomiechen/dmon)
|
|
7
|
+
[](https://pypi.org/project/python-dmon/)
|
|
8
|
+
[](https://deepwiki.com/atomiechen/dmon)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
A lightweight, cross-platform process manager for local services and development workflows.
|
|
12
|
+
Run any command as a background *task*, or supervise a stack with readiness checks
|
|
13
|
+
and repair failed members while healthy services keep running. Logging and log
|
|
14
|
+
rotation are built in.
|
|
15
|
+
|
|
16
|
+
For developers and coding agents, dmon records process identities and exposes
|
|
17
|
+
JSON status so later sessions can inspect and reuse existing services.
|
|
18
|
+
See [coding-agent setup](https://github.com/atomiechen/dmon/blob/main/docs/agent-setup.md).
|
|
19
|
+
|
|
20
|
+
Shipped as the CLI tool `dmon`.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- 🖥️ **Cross-platform:** Works on Linux, macOS, and Windows.
|
|
26
|
+
- ⚡ **Lightweight:** No daemon service or container runtime required.
|
|
27
|
+
- 🧩 **Flexible tasks:** Tasks can be configured in `pyproject.toml` or `dmon.yaml`; or run ad-hoc commands directly.
|
|
28
|
+
- 🔗 **Supervised stacks:** Start dependent tasks in order, wait for HTTP, TCP,
|
|
29
|
+
or command readiness, and report runtime degradation.
|
|
30
|
+
- 🌙 **Foreground or detached:** Keep a stack attached for development, or run
|
|
31
|
+
it under a recoverable background supervisor with `dmon stack up -d` and
|
|
32
|
+
`dmon stack down`.
|
|
33
|
+
- ⏱️ **Reusable readiness:** Wait for configured tasks or direct HTTP, TCP, and
|
|
34
|
+
command probes from scripts and deployment workflows.
|
|
35
|
+
- 🪵 **Logging & log rotation:** Keep active log files manageable, with optional archive retention limits.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## Demos
|
|
39
|
+
|
|
40
|
+
The demos below cover everyday task management and supervised stacks. Both use this `dmon.yaml` and a small [heartbeat program](https://github.com/atomiechen/dmon/blob/main/scripts/recording/service.py):
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
tasks:
|
|
44
|
+
api: [python, -u, service.py, api]
|
|
45
|
+
worker: [python, -u, service.py, worker]
|
|
46
|
+
stacks:
|
|
47
|
+
dev: [api, worker]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Everyday tasks.** Run a command directly with `run` (no configuration needed),
|
|
51
|
+
then use `start`, `status`, and `stop` for a configured task. `exec` runs a
|
|
52
|
+
configured task in the foreground; Ctrl-C ends it. In this clip, `stop --all`
|
|
53
|
+
stops the sole ad-hoc task before the configured API is started.
|
|
54
|
+
|
|
55
|
+

|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
**Keep healthy services running.** Start a stack, deliberately stop its worker,
|
|
59
|
+
and repair that member. The API keeps the same PID and its counter continues;
|
|
60
|
+
`stack down` stops both members. The lower panes show real files and live logs.
|
|
61
|
+
|
|
62
|
+

|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
`dmon` requires Python 3.8+ and is available as [`python-dmon`](https://pypi.org/project/python-dmon/) on PyPI.
|
|
69
|
+
Managed commands can use any language.
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
pip install python-dmon
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
We recommend installing into an isolated environment, e.g., with `uv` / `pipx`:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
# Install globally with uv tool
|
|
79
|
+
uv tool install python-dmon
|
|
80
|
+
|
|
81
|
+
# Or with pipx
|
|
82
|
+
pipx install python-dmon
|
|
83
|
+
|
|
84
|
+
# Add as a dev dependency in your project
|
|
85
|
+
uv add --dev python-dmon
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
You can also run dmon without installing it permanently:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
# With uvx (uv tool run)
|
|
92
|
+
uvx python-dmon
|
|
93
|
+
|
|
94
|
+
# Or with pipx
|
|
95
|
+
pipx run python-dmon
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
To get the latest features, install from source:
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
pip install git+https://github.com/atomiechen/dmon.git
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
For coding agents, see the [setup instructions](https://github.com/atomiechen/dmon/blob/main/docs/agent-setup.md) and the
|
|
105
|
+
[portable skill](https://github.com/atomiechen/dmon/blob/main/skills/dmon/SKILL.md). The skill is installed separately from the CLI.
|
|
106
|
+
|
|
107
|
+
## Getting Started
|
|
108
|
+
|
|
109
|
+
### Prepare Configuration
|
|
110
|
+
|
|
111
|
+
Create a `dmon.yaml` file:
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
tasks:
|
|
115
|
+
app: ["python", "-u", "server.py"] # exec form
|
|
116
|
+
# app: "python -u server.py" # or a shell string
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Without `--config`, dmon searches the current directory and its parents for
|
|
120
|
+
`dmon.yaml`, `dmon.yml`, or `pyproject.toml`. See the
|
|
121
|
+
[configuration reference](https://github.com/atomiechen/dmon/blob/main/docs/configuration.md)
|
|
122
|
+
for TOML, environments, paths, defaults, and log rotation.
|
|
123
|
+
|
|
124
|
+
### Run tasks
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
dmon start app # Start in the background
|
|
128
|
+
dmon stop app # Stop the recorded process tree
|
|
129
|
+
dmon restart app
|
|
130
|
+
dmon status app
|
|
131
|
+
dmon exec app # Run in this terminal; Ctrl-C ends it
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`exec` runs one configured command directly, without registering a managed
|
|
135
|
+
background task. Use `start` to keep it discoverable through `status` and `list`.
|
|
136
|
+
You can pass multiple names to the other task commands. Multi-task `start` is
|
|
137
|
+
best-effort: successful tasks stay running if another fails. For related
|
|
138
|
+
services with ordered startup and rollback, use a stack.
|
|
139
|
+
|
|
140
|
+
### Run a stack
|
|
141
|
+
|
|
142
|
+
```yaml
|
|
143
|
+
tasks:
|
|
144
|
+
api:
|
|
145
|
+
cmd: [python, api.py]
|
|
146
|
+
ready:
|
|
147
|
+
http: http://127.0.0.1:8000/health
|
|
148
|
+
worker:
|
|
149
|
+
cmd: [python, worker.py]
|
|
150
|
+
depends_on: [api]
|
|
151
|
+
stacks:
|
|
152
|
+
dev: [api, worker]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
```sh
|
|
156
|
+
dmon stack up dev # Foreground; Ctrl-C stops the stack
|
|
157
|
+
# Or keep it running under a background supervisor:
|
|
158
|
+
dmon stack up -d dev
|
|
159
|
+
dmon stack status dev
|
|
160
|
+
dmon stack logs --tail 100 dev
|
|
161
|
+
dmon stack repair dev worker --format json # Replace an exited member
|
|
162
|
+
dmon stack down dev
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Stack startup waits for readiness and rolls back tasks it started if startup
|
|
166
|
+
fails. After startup, an exited member degrades the stack while healthy peers
|
|
167
|
+
keep running. `repair` replaces that member through its live supervisor, so
|
|
168
|
+
later `down` includes the replacement. It reuses the supervisor's launch
|
|
169
|
+
configuration and environment; separately running `dmon start worker` does not
|
|
170
|
+
repair stack membership.
|
|
171
|
+
|
|
172
|
+
See [task and stack lifecycle](https://github.com/atomiechen/dmon/blob/main/docs/ownership.md)
|
|
173
|
+
for fail-fast behavior, detached restart, recovery, and ownership limits. Docker
|
|
174
|
+
Compose is still appropriate when container behavior itself must be tested.
|
|
175
|
+
|
|
176
|
+
### Wait for readiness
|
|
177
|
+
|
|
178
|
+
`dmon wait` checks readiness without starting or stopping anything. Configured
|
|
179
|
+
tasks need a `ready` probe and must already be managed by `start` or a stack:
|
|
180
|
+
|
|
181
|
+
```sh
|
|
182
|
+
dmon wait api
|
|
183
|
+
dmon wait api --timeout 60 --interval 0.5
|
|
184
|
+
|
|
185
|
+
# Direct probes need no configuration
|
|
186
|
+
dmon wait --http http://127.0.0.1:8000/health
|
|
187
|
+
dmon wait --tcp 127.0.0.1:5432
|
|
188
|
+
dmon wait --timeout 30 --command -- python healthcheck.py --verbose
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Put dmon options before `--command`; the optional second `--` marks the child
|
|
192
|
+
command. See [readiness configuration](https://github.com/atomiechen/dmon/blob/main/docs/configuration.md#readiness)
|
|
193
|
+
for probe options, listener ownership checks, and wait results.
|
|
194
|
+
|
|
195
|
+
### Run an ad-hoc command
|
|
196
|
+
|
|
197
|
+
```sh
|
|
198
|
+
dmon run --name myserver python -u server.py
|
|
199
|
+
dmon run --name timer -- python -c 'import time; time.sleep(30)'
|
|
200
|
+
dmon run --shell echo "Hello World"
|
|
201
|
+
dmon run --cwd /path/to/script bash myscript.sh
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
No configuration is needed. Without `--name`, dmon uses the fixed name
|
|
205
|
+
`default_run` to prevent duplicate runs.
|
|
206
|
+
|
|
207
|
+
### List recorded tasks and their status
|
|
208
|
+
|
|
209
|
+
```sh
|
|
210
|
+
dmon list
|
|
211
|
+
dmon status app --format json
|
|
212
|
+
dmon list --format json
|
|
213
|
+
dmon stack status dev --format json
|
|
214
|
+
dmon stack list --format json
|
|
215
|
+
dmon wait api --format json
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
JSON is written only to stdout; actionable diagnostics remain on stderr. The
|
|
219
|
+
payload has a top-level `ok` field and a `tasks`, `stacks`, or `waits` array.
|
|
220
|
+
Inspection results contain `name`, `ok`, `error`, and an optional `snapshot`;
|
|
221
|
+
wait results contain the target, outcome, reason, elapsed time, and attempt
|
|
222
|
+
count. Existing exit-code semantics are unchanged. Interactive and streaming
|
|
223
|
+
commands do not offer JSON output.
|
|
224
|
+
|
|
225
|
+
### Python API
|
|
226
|
+
|
|
227
|
+
The same task lifecycle and inspection logic is available without parsing CLI
|
|
228
|
+
output:
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
from dmon import Dmon
|
|
232
|
+
|
|
233
|
+
client = Dmon(config="dmon.yaml")
|
|
234
|
+
started = client.start("app")
|
|
235
|
+
task = client.status("app")
|
|
236
|
+
stacks = client.list_stacks()
|
|
237
|
+
client.stop("app")
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
`client.wait("app", timeout=30)` also checks readiness when `app` has a
|
|
241
|
+
configured `ready` probe. API calls are synchronous and silent.
|
|
242
|
+
`start`, `stop`, and `restart` return an immutable `BatchResult`; `status`
|
|
243
|
+
and `stack_status` return `TaskResult` and `StackResult`. List and wait methods
|
|
244
|
+
return tuples of their corresponding result types. Expected runtime states such
|
|
245
|
+
as missing or exited metadata are results, while invalid configuration raises
|
|
246
|
+
`DmonConfigError`. The initial API intentionally does not start a supervised
|
|
247
|
+
stack or create implicit background threads.
|
|
248
|
+
|
|
249
|
+
## Documentation
|
|
250
|
+
|
|
251
|
+
Start with the [documentation index](https://github.com/atomiechen/dmon/blob/main/docs/README.md):
|
|
252
|
+
|
|
253
|
+
- [Configuration](https://github.com/atomiechen/dmon/blob/main/docs/configuration.md): task selection, YAML/TOML, environments, readiness, and logs.
|
|
254
|
+
- [Task and stack lifecycle](https://github.com/atomiechen/dmon/blob/main/docs/ownership.md): startup, repair, recovery, and process ownership.
|
|
255
|
+
- [Coding-agent setup](https://github.com/atomiechen/dmon/blob/main/docs/agent-setup.md): install the workflow and continue across sessions.
|
|
256
|
+
|
|
257
|
+
## Development
|
|
258
|
+
|
|
259
|
+
See [CONTRIBUTING.md](https://github.com/atomiechen/dmon/blob/main/CONTRIBUTING.md) for architecture, behavioral contracts,
|
|
260
|
+
validation, and the release workflow. Process, signal, log-rotation, and stack
|
|
261
|
+
changes must also pass the reproducible [manual test lab](https://github.com/atomiechen/dmon/blob/main/tests/manual/README.md).
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
[dmon](https://github.com/atomiechen/dmon) © 2025 by [Atomie CHEN](https://github.com/atomiechen) is licensed under the [MIT License](https://github.com/atomiechen/dmon/blob/main/LICENSE).
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-dmon"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "A lightweight, cross-platform
|
|
3
|
+
version = "0.5.0"
|
|
4
|
+
description = "A lightweight, cross-platform process manager for background tasks, local service stacks, and partial recovery."
|
|
5
5
|
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
6
8
|
authors = [
|
|
7
9
|
{ name = "Atomie CHEN", email = "atomic_cwh@163.com" }
|
|
8
10
|
]
|
|
@@ -15,12 +17,12 @@ dependencies = [
|
|
|
15
17
|
"termcolor>=2.4.0",
|
|
16
18
|
"tomli>=2.2.1 ; python_full_version < '3.11'",
|
|
17
19
|
]
|
|
18
|
-
keywords = ["
|
|
20
|
+
keywords = ["dmon", "process manager", "daemon", "background", "supervisor", "local development", "readiness", "service management", "coding agents"]
|
|
19
21
|
|
|
20
22
|
[project.urls]
|
|
21
|
-
"Homepage" = "https://github.com/atomiechen/
|
|
22
|
-
"Bug Tracker" = "https://github.com/atomiechen/
|
|
23
|
-
Changelog = "https://github.com/atomiechen/
|
|
23
|
+
"Homepage" = "https://github.com/atomiechen/dmon"
|
|
24
|
+
"Bug Tracker" = "https://github.com/atomiechen/dmon/issues"
|
|
25
|
+
Changelog = "https://github.com/atomiechen/dmon/blob/main/CHANGELOG.md"
|
|
24
26
|
|
|
25
27
|
[project.scripts]
|
|
26
28
|
dmon = "dmon.__main__:main"
|