aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md350
-rw-r--r--src/main.rs21
2 files changed, 362 insertions, 9 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..cbc8fe5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,350 @@
1# Demon - Background Process Manager
2
3A lightweight, intuitive CLI tool for spawning, managing, and monitoring background processes on Linux systems. Perfect for development servers, long-running tasks, and automation workflows.
4
5## ✨ Features
6
7- **Simple Process Management**: Start, stop, and monitor background processes with ease
8- **Persistent Logging**: Automatic stdout/stderr capture to files
9- **Real-time Monitoring**: Tail logs in real-time with file watching
10- **Process Lifecycle**: Graceful termination with SIGTERM/SIGKILL fallback
11- **Machine-readable Output**: Perfect for scripting and LLM agent integration
12- **Zero Configuration**: Works out of the box, no setup required
13
14## 🚀 Installation
15
16### From Source
17```bash
18git clone https://github.com/yourusername/demon
19cd demon
20cargo install --path .
21```
22
23### From Crates.io (Coming Soon)
24```bash
25cargo install demon
26```
27
28## 🎯 Quick Start
29
30```bash
31# Start a development server
32demon run web-server python -m http.server 8080
33
34# Monitor the logs in real-time
35demon tail web-server
36
37# Check what's running
38demon list
39
40# Stop the server
41demon stop web-server
42
43# Clean up finished processes
44demon clean
45```
46
47## 📋 Command Reference
48
49### `demon run <id> [command...]`
50Spawn a background process with the given identifier.
51
52```bash
53# Basic usage
54demon run my-app ./my-application
55
56# Development server
57demon run dev-server npm run dev
58
59# Complex commands (use -- to separate)
60demon run backup-job -- rsync -av /data/ /backup/
61
62# Long-running computation
63demon run ml-training python train_model.py --epochs 100
64```
65
66### `demon list [--quiet]`
67List all managed processes and their status.
68
69```bash
70# Human-readable format
71demon list
72
73# Machine-readable format (for scripts/agents)
74demon list --quiet
75```
76
77### `demon status <id>`
78Show detailed status information for a specific process.
79
80```bash
81demon status web-server
82```
83
84### `demon stop <id> [--timeout <seconds>]`
85Stop a running process gracefully (SIGTERM, then SIGKILL if needed).
86
87```bash
88# Default 10-second timeout
89demon stop web-server
90
91# Custom timeout
92demon stop slow-service --timeout 30
93```
94
95### `demon tail <id> [--stdout] [--stderr]`
96Follow log files in real-time (like `tail -f`).
97
98```bash
99# Follow both stdout and stderr
100demon tail web-server
101
102# Follow only stdout
103demon tail web-server --stdout
104
105# Follow only stderr
106demon tail web-server --stderr
107```
108
109### `demon cat <id> [--stdout] [--stderr]`
110Display the complete contents of log files.
111
112```bash
113# Show both logs
114demon cat web-server
115
116# Show only stdout
117demon cat web-server --stdout
118```
119
120### `demon clean`
121Remove orphaned files from processes that are no longer running.
122
123```bash
124demon clean
125```
126
127### `demon llm`
128Output comprehensive usage guide optimized for LLM consumption.
129
130```bash
131demon llm
132```
133
134## 🎮 Use Cases
135
136### Development Workflows
137Perfect for managing development servers and build processes:
138
139```bash
140# Start multiple development services
141demon run api-server npm run dev
142demon run frontend yarn start
143demon run db-server docker run -p 5432:5432 postgres
144
145# Monitor everything
146demon list
147demon tail api-server --stderr # Watch for errors
148```
149
150### LLM Agent Integration
151Designed for seamless automation and LLM agent workflows:
152
153```bash
154# Agents can start long-running processes
155demon run data-processor python process_large_dataset.py
156
157# Check status programmatically
158if demon status data-processor | grep -q "RUNNING"; then
159 echo "Processing is still running"
160fi
161
162# Get machine-readable process list
163demon list --quiet | while IFS=: read id pid status; do
164 echo "Process $id ($pid) is $status"
165done
166```
167
168### Background Tasks & Scripts
169Ideal for CI/CD, backups, and system maintenance:
170
171```bash
172# Database backup
173demon run nightly-backup -- pg_dump mydb > backup.sql
174
175# Log file processing
176demon run log-analyzer tail -f /var/log/app.log | grep ERROR
177
178# System monitoring
179demon run monitor -- iostat -x 1
180```
181
182### DevOps & System Administration
183Manage services without complex init systems:
184
185```bash
186# Application deployment
187demon run app-server ./deploy.sh production
188
189# Health monitoring
190demon run health-check -- while true; do curl -f http://localhost:8080/health || exit 1; sleep 30; done
191
192# Resource monitoring
193demon run resource-monitor -- top -b -n1 | head -20
194```
195
196## 🏗️ How It Works
197
198When you run `demon run web-server python -m http.server 8080`:
199
2001. **Process Creation**: Spawns the process detached from your terminal
2012. **File Management**: Creates three files:
202 - `web-server.pid` - Contains the process ID and command
203 - `web-server.stdout` - Captures standard output
204 - `web-server.stderr` - Captures error output
2053. **Process Monitoring**: Tracks process lifecycle independently
2064. **Log Management**: Files persist after process termination for inspection
207
208## 🤖 LLM Agent Integration
209
210Demon is specifically designed to work seamlessly with LLM agents and automation tools:
211
212### Machine-Readable Output
213```bash
214# Get process status in parseable format
215demon list --quiet
216# Output: web-server:12345:RUNNING
217# backup-job:12346:DEAD
218```
219
220### Scripting Examples
221```bash
222# Start service if not running
223demon list --quiet | grep -q "web-server:" || demon run web-server python -m http.server
224
225# Wait for process to finish
226while demon list --quiet | grep -q "backup-job:.*:RUNNING"; do
227 sleep 5
228done
229
230# Get all running processes
231demon list --quiet | grep ":RUNNING" | cut -d: -f1
232```
233
234### Error Handling
235```bash
236# Check if process started successfully
237if demon run api-server ./start-api.sh; then
238 echo "API server started successfully"
239 demon tail api-server & # Monitor in background
240else
241 echo "Failed to start API server"
242 exit 1
243fi
244```
245
246## 📁 File Management
247
248### File Locations
249All files are created in the current working directory:
250- `<id>.pid` - Process ID and command information
251- `<id>.stdout` - Standard output log
252- `<id>.stderr` - Standard error log
253
254### Cleanup
255- Files persist after process termination for inspection
256- Use `demon clean` to remove files from dead processes
257- Consider adding `*.pid`, `*.stdout`, `*.stderr` to `.gitignore`
258
259### Log Rotation
260- Demon doesn't handle log rotation internally
261- For long-running processes, implement rotation in your application
262- Or use external tools like `logrotate`
263
264## 🔧 Advanced Usage
265
266### Process Management
267```bash
268# Graceful shutdown with custom timeout
269demon stop long-running-task --timeout 60
270
271# Force kill if process is stuck
272demon stop stuck-process --timeout 1
273```
274
275### Monitoring & Debugging
276```bash
277# Monitor multiple processes
278for id in web-server api-server worker; do
279 demon tail $id --stderr &
280done
281
282# Check resource usage
283demon run monitor -- ps aux | grep my-app
284demon cat monitor
285```
286
287### Integration with System Tools
288```bash
289# Use with systemd
290demon run my-service systemctl --user start my-app
291
292# Use with Docker
293demon run container -- docker run -d --name myapp nginx
294
295# Use with tmux/screen for complex setups
296demon run dev-env -- tmux new-session -d 'npm run dev'
297```
298
299## ⚠️ System Requirements
300
301- **Operating System**: Linux (uses `kill` command for process management)
302- **Rust**: 1.70+ (for building from source)
303- **Permissions**: Standard user permissions (no root required)
304
305## 🔒 Security Considerations
306
307- Demon runs processes with the same permissions as the calling user
308- PID files contain process information - protect accordingly
309- Log files may contain sensitive information from your applications
310- No network access or elevated privileges required
311
312## 🤝 Contributing
313
314We welcome contributions! Here's how to get started:
315
3161. **Fork the repository**
3172. **Create a feature branch**: `git checkout -b feature/amazing-feature`
3183. **Make your changes**
3194. **Run tests**: `cargo test`
3205. **Format code**: `cargo fmt`
3216. **Submit a pull request**
322
323### Development Setup
324```bash
325git clone https://github.com/yourusername/demon
326cd demon
327cargo build
328cargo test
329```
330
331## 📝 License
332
333This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
334
335## 🐛 Bug Reports & Feature Requests
336
337Found a bug or have a feature idea? Please open an issue on [GitHub Issues](https://github.com/yourusername/demon/issues).
338
339## 📚 Similar Tools
340
341- **pm2** - Process manager for Node.js applications
342- **supervisor** - Process control system for Unix
343- **systemd** - System and service manager for Linux
344- **screen/tmux** - Terminal multiplexers
345
346Demon focuses on simplicity, LLM integration, and developer experience over complex process management features.
347
348---
349
350**Built with ❤️ in Rust** \ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index bedcb74..e90bfed 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -80,12 +80,15 @@ impl PidFile {
80 let lines: Vec<&str> = contents.lines().collect(); 80 let lines: Vec<&str> = contents.lines().collect();
81 81
82 if lines.is_empty() { 82 if lines.is_empty() {
83 return Err(PidFileReadError::FileInvalid("PID file is empty".to_string())); 83 return Err(PidFileReadError::FileInvalid(
84 "PID file is empty".to_string(),
85 ));
84 } 86 }
85 87
86 let pid = lines[0].trim().parse::<u32>().map_err(|_| { 88 let pid = lines[0]
87 PidFileReadError::FileInvalid("Invalid PID on first line".to_string()) 89 .trim()
88 })?; 90 .parse::<u32>()
91 .map_err(|_| PidFileReadError::FileInvalid("Invalid PID on first line".to_string()))?;
89 92
90 let command: Vec<String> = lines[1..].iter().map(|line| line.to_string()).collect(); 93 let command: Vec<String> = lines[1..].iter().map(|line| line.to_string()).collect();
91 94
@@ -647,7 +650,10 @@ fn list_daemons(quiet: bool) -> Result<()> {
647 println!("{}:{}:{}", id, pid_file_data.pid, status); 650 println!("{}:{}:{}", id, pid_file_data.pid, status);
648 } else { 651 } else {
649 let command = pid_file_data.command_string(); 652 let command = pid_file_data.command_string();
650 println!("{:<20} {:<8} {:<10} {}", id, pid_file_data.pid, status, command); 653 println!(
654 "{:<20} {:<8} {:<10} {}",
655 id, pid_file_data.pid, status, command
656 );
651 } 657 }
652 } 658 }
653 Err(PidFileReadError::FileNotFound) => { 659 Err(PidFileReadError::FileNotFound) => {
@@ -665,10 +671,7 @@ fn list_daemons(quiet: bool) -> Result<()> {
665 if quiet { 671 if quiet {
666 println!("{}:INVALID:ERROR", id); 672 println!("{}:INVALID:ERROR", id);
667 } else { 673 } else {
668 println!( 674 println!("{:<20} {:<8} {:<10} {}", id, "INVALID", "ERROR", reason);
669 "{:<20} {:<8} {:<10} {}",
670 id, "INVALID", "ERROR", reason
671 );
672 } 675 }
673 } 676 }
674 Err(PidFileReadError::IoError(_)) => { 677 Err(PidFileReadError::IoError(_)) => {