Skip to content

warptengood/qara

Repository files navigation

qara banner
PyPI version Python versions License CI

Watch any process. Get notified on Telegram. Control it remotely.

qara is a lightweight daemon that monitors processes and sends real-time notifications to Telegram. Start a long-running job, close your laptop, and stay in control from your phone.

Built for ML practitioners who run multi-hour training jobs, but works with any process.

qara run python train.py --name "gpt-finetune"
# => Telegram: "Process 'gpt-finetune' started (PID 41592)"
# => ... hours later ...
# => Telegram: "Process 'gpt-finetune' finished (exit 0, 3h 42m)"
Telegram notifications for an attached process

Features

  • Spawn or attach — start a new process with qara run or monitor an existing one with qara attach <pid>
  • Telegram notifications — get notified on start, finish, and crash with configurable stdout tail
  • Remote control — send /status, /kill, /history, /logs from Telegram
  • Daemon mode — runs as a user-level service (systemd, launchd) — no root required
  • JSON output--format json on status and history for scripting

Quickstart

Install

# Install globally (recommended)
pipx install qara

# Or with uv
uv pip install qara

Configure

qara config init

This creates ~/.config/qara/config.toml. Open it and add your Telegram bot token and user ID:

[telegram]
bot_token = "123456:ABC-DEF..."
allowed_user_ids = [your_telegram_user_id]
How to get a bot token and user ID
  1. Message @BotFather on Telegram and send /newbot
  2. Follow the prompts to name your bot — you'll receive a token like 123456:ABC-DEF...
  3. To find your user ID, message @userinfobot and it will reply with your numeric ID
  4. Important: Send any message to your new bot first so it can message you back

Start the daemon

qara daemon start

Run a process

qara run python train.py --name "experiment-1"

That's it. You'll receive Telegram notifications when the process starts, finishes, or crashes.

Usage

Process management

# Run a process
qara run python train.py --name "my-job"

# Attach to an existing process
qara attach 12345 --name "background-job"

# List watched processes
qara status
qara status --format json

# View completed runs
qara history --last 10
qara history --format json

Telegram commands

Once the daemon is running, send these commands to your bot:

Command Description
/status List all watched processes
/kill <name> Send SIGTERM to a process (escalates to SIGKILL)
/history Show recent completed runs
/logs <name> Get last N lines of stdout
Telegram /logs and /kill commands in action

Daemon management

qara daemon start              # Start in background
qara daemon start --foreground  # Start in foreground (for systemd/launchd)
qara daemon stop               # Stop the daemon
qara daemon status             # Check if daemon is running

Install as a system service

# Auto-detects systemd (Linux) or launchd (macOS)
qara install

# Preview what would be installed
qara install --dry-run

# Remove the service
qara uninstall

Configuration

Full config.toml reference:

[daemon]
log_level = "INFO"  # DEBUG, INFO, WARNING, ERROR

[telegram]
bot_token = "YOUR_BOT_TOKEN"
allowed_user_ids = [123456789]

[telegram.notifications]
on_start = true
on_finish = true
on_crash = true
stdout_tail_lines = 20  # lines of stdout included in finish notification

[commands]
enabled = ["status", "kill", "restart"]
kill_timeout_seconds = 10

[commands.allowed_scripts]
# alias = "/absolute/path/to/script.py"

Architecture

qara daemon start
      │
      ▼
┌─────────────┐     ┌──────────────┐     ┌──────────────┐
│   Watcher    │────▶│  EventEngine │────▶│  Telegram    │
│  (per proc)  │     │  (pub/sub)   │     │  Channel     │
└─────────────┘     └──────┬───────┘     └──────────────┘
                           │
                    ┌──────┴───────┐
                    │   Plugins    │
                    │ (GPU, loss)  │
                    └──────────────┘
      ▲
      │ IPC (Unix socket)
      │
  qara run / qara status / ...
  • Watcher spawns or attaches to processes via asyncio.create_subprocess_exec
  • EventEngine is sequential async pub/sub — handlers receive events in subscription order
  • Plugins subscribe directly to the engine and receive all events including stdout/stderr lines
  • NotificationBus filters internal events before routing to channels
  • IPC uses newline-delimited JSON over Unix sockets (Linux/macOS)

Development

git clone https://github.com/warptengood/qara
cd qara
uv sync --group dev

# Run checks
uv run ruff check src/       # lint
uv run ruff format src/      # format
uv run mypy src/             # type check
uv run pytest                # tests

See CONTRIBUTING.md for guidelines.

License

MIT — see LICENSE for details.

About

Cross-platform process monitor daemon with Telegram notifications and remote control. Run long jobs, close your laptop, stay in control from your phone.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages