home / skills / terrylica / cc-skills / bot-process-control
This skill manages the Gmail Commander bot daemon and digest schedules, enabling start, stop, restart, status, and log access.
npx playbooks add skill terrylica/cc-skills --skill bot-process-controlReview the files below or copy the command above to add this skill to your agents.
---
name: bot-process-control
description: Gmail Commander daemon lifecycle - start, stop, restart, status, logs, launchd plist management. TRIGGERS - bot start, bot stop, bot restart, bot status, bot logs, launchd, daemon, process control, gmail-commander service.
allowed-tools: Read, Bash, Grep, Glob
---
# Bot Process Control
Manage the Gmail Commander bot daemon and scheduled digest via launchd.
## Mandatory Preflight
### Step 1: Check Current Process Status
```bash
echo "=== Gmail Commander Processes ==="
pgrep -fl "gmail-commander" 2>/dev/null || echo "No processes found"
echo ""
echo "=== launchd Status ==="
launchctl list | grep gmail-commander 2>/dev/null || echo "No launchd jobs"
echo ""
echo "=== PID Files ==="
cat /tmp/gmail-commander-bot.pid 2>/dev/null && echo " (bot)" || echo "No bot PID file"
cat /tmp/gmail-digest.pid 2>/dev/null && echo " (digest)" || echo "No digest PID file"
```
## Two Services
| Service | Type | Trigger | PID File |
| ---------- | ------------- | -------------------------- | ---------------------------- |
| Bot Daemon | KeepAlive | Always-on (grammY polling) | /tmp/gmail-commander-bot.pid |
| Digest | StartInterval | Every 6 hours (21600s) | /tmp/gmail-digest.pid |
## launchd Plist Templates
### Bot Daemon — `com.terryli.gmail-commander-bot.plist`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.terryli.gmail-commander-bot</string>
<key>ProgramArguments</key>
<array>
<string>/Users/terryli/own/amonic/bin/gmail-commander-bot</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<dict>
<key>NetworkState</key>
<true/>
</dict>
<key>StandardOutPath</key>
<string>/Users/terryli/own/amonic/logs/bot-stdout.log</string>
<key>StandardErrorPath</key>
<string>/Users/terryli/own/amonic/logs/bot-stderr.log</string>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/Users/terryli/.local/share/mise/shims:/usr/local/bin:/usr/bin:/bin</string>
</dict>
<key>ThrottleInterval</key>
<integer>10</integer>
</dict>
</plist>
```
### Scheduled Digest — `com.terryli.gmail-commander-digest.plist`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.terryli.gmail-commander-digest</string>
<key>ProgramArguments</key>
<array>
<string>/Users/terryli/own/amonic/bin/gmail-commander-digest</string>
</array>
<key>StartInterval</key>
<integer>21600</integer>
<key>StandardOutPath</key>
<string>/Users/terryli/own/amonic/logs/digest-stdout.log</string>
<key>StandardErrorPath</key>
<string>/Users/terryli/own/amonic/logs/digest-stderr.log</string>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/Users/terryli/.local/share/mise/shims:/usr/local/bin:/usr/bin:/bin</string>
</dict>
</dict>
</plist>
```
## Quick Operations
### Start Bot
```bash
launchctl load ~/Library/LaunchAgents/com.terryli.gmail-commander-bot.plist
```
### Stop Bot
```bash
launchctl unload ~/Library/LaunchAgents/com.terryli.gmail-commander-bot.plist
```
### Restart Bot
```bash
launchctl unload ~/Library/LaunchAgents/com.terryli.gmail-commander-bot.plist
launchctl load ~/Library/LaunchAgents/com.terryli.gmail-commander-bot.plist
```
### Force Kill (Emergency)
```bash
pkill -f "gmail-commander.*bot.ts"
rm -f /tmp/gmail-commander-bot.pid
```
### View Logs
```bash
# Recent bot output
tail -50 ~/own/amonic/logs/bot-stderr.log
# Recent digest output
tail -50 ~/own/amonic/logs/digest-stderr.log
# Audit log (NDJSON)
cat ~/own/amonic/logs/audit/$(date +%Y-%m-%d).ndjson | jq .
```
## System Resources (Expected)
- **Memory**: ~20-30 MB RSS (Bun runtime + grammY)
- **CPU**: Negligible (idle polling, wakes on message)
- **Network**: Minimal (single long-poll connection to Telegram API)
- **Disk**: ~1 MB/day audit logs (14-day rotation)
## Post-Change Checklist
- [ ] YAML frontmatter valid (no colons in description)
- [ ] Trigger keywords current
- [ ] Path patterns use $HOME not hardcoded paths
- [ ] launchd plist templates match actual launcher scripts
This skill manages the Gmail Commander daemon and its scheduled digest on macOS using launchd. It provides lifecycle commands to start, stop, restart, check status, view logs, and manage launchd plist files for both the always-on bot and the periodic digest. It focuses on safe process control, PID handling, and simple troubleshooting steps.
The skill inspects running processes, PID files, and launchd job listings to determine service state. It can load/unload the two launchd plists (bot daemon and scheduled digest), tail relevant logs, and perform emergency force-kill and PID cleanup when needed. It also includes plist templates and resource expectations to help validate deployments.
How do I check whether the bot or digest is running?
Run pgrep -fl gmail-commander, check launchctl list for gmail-commander jobs, and inspect /tmp/gmail-commander-bot.pid and /tmp/gmail-digest.pid for active PID files.
What if launchctl load fails after plist changes?
Unload the job, validate plist syntax and EnvironmentVariables, replace hardcoded paths with $HOME, then load again. Tail stderr logs for immediate errors.
When should I force kill the bot?
Only if the bot is unresponsive to unload/load and pgrep shows a hung process. Use pkill -f with the process pattern and remove the corresponding /tmp PID file after confirming termination.