Metadata-Version: 2.4
Name: svci
Version: 1.1.1
Summary: A tool to install Python as SystemD or LaunchD service
Author: PexMor
License-Expression: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: configargparse
Requires-Dist: jeepney ; sys_platform == 'linux'
Requires-Python: >=3.14
Project-URL: Homepage, https://github.com/PexMor/svci
Project-URL: Repository, https://github.com/PexMor/svci
Project-URL: Issues, https://github.com/PexMor/svci/issues
Description-Content-Type: text/markdown

# svci

A tool to install Python apps as systemd (Linux) or launchd (macOS) services.

## Features

- Cross-platform: systemd on Linux, launchd on macOS
- Three service modes: `user`, `system`, and `system-at-user`
- ConfigArgParse-based CLI with CLI args, environment variables, and TOML config file support
- `--pyproject` flag to read config from `[tool.svci]` in `pyproject.toml`
- Built-in templates with customizable overrides
- Dry-run by default, `--install` to write to disk
- DIY mode (`--diy`) generates a deployment bundle with service file + README
- Pre-flight checks: `.venv` detection, linger status (Linux), existing service detection
- Colored unified diff before overwriting existing services
- D-Bus integration for systemd control (via jeepney)
- Modern launchctl commands (bootstrap/bootout/kickstart) for macOS

## Installation

```bash
pip install svci
```

Or with [uv](https://docs.astral.sh/uv/):

```bash
uv tool install svci
```

## Usage

### Dry run (preview the generated service file)

```bash
svci \
  --working-dir /path/to/app \
  --run-cmd "uv run app --host 127.0.0.1 --port 7867"
```

### Install a user service

```bash
svci \
  --install \
  --enable \
  --start \
  --working-dir /path/to/app \
  --run-cmd "uv run app --host 127.0.0.1 --port 7867"
```

### Install a system-wide service

```bash
sudo svci \
  --install \
  --service-mode system \
  --name my-app \
  --working-dir /srv/my-app \
  --run-cmd "uv run app --host 127.0.0.1 --port 7867"
```

### Install a system-wide name@user service

```bash
sudo svci \
  --install \
  --service-mode system-at-user \
  --name my-app \
  --user myuser \
  --working-dir /srv/my-app \
  --run-cmd "uv run app --host 127.0.0.1 --port 7867"
```

### Show platform-specific management commands

```bash
svci --help-platform --name my-app --service-mode user
```

This prints all the commands you need to manage the service (enable, start, stop, restart, logs, remove), tailored to your platform (systemd or launchd) and service mode. Works standalone or after install/dry-run.

### Generate a DIY deployment bundle

```bash
svci \
  --diy \
  --working-dir /path/to/app \
  --run-cmd "uv run app --host 127.0.0.1 --port 7867"
```

This creates a `~/tmp/<name>/` directory with the service file and a README with manual deployment instructions.

### Using pyproject.toml

Add a `[tool.svci]` section to your project's `pyproject.toml`:

```toml
[tool.svci]
name = "my-web-app"
description = "FastAPI app running via uv"
run_cmd = "uv run main.py --host 127.0.0.1 --port 8000"
service_mode = "user"

[tool.svci.environment]
DEBUG = "false"
PORT = "8000"
DATABASE_URL = "postgresql://localhost/mydb"

[tool.svci.systemd]
restart = "always"
restart_sec = 3

[tool.svci.launchd]
run_at_load = true
```

Then deploy with a single command from your project directory:

```bash
svci --pyproject --install --enable --start
```

Or point to a specific file:

```bash
svci --pyproject /path/to/pyproject.toml --install
```

When `--pyproject` is used, `working_dir` defaults to the directory containing the `pyproject.toml`. CLI arguments always override values from `pyproject.toml`.

#### `[tool.svci]` reference

| Key | Type | Description |
|-----|------|-------------|
| `name` | string | Service name (default: directory name) |
| `description` | string | Service description |
| `run_cmd` | string | Command to execute |
| `working_dir` | string | Working directory (default: pyproject.toml directory) |
| `service_mode` | string | `"user"`, `"system"`, or `"system-at-user"` |
| `user` | string | User for system modes |
| `group` | string | Group for system modes (Linux only) |
| `template` | string | Path to custom template file |

| Section | Key | Type | Description |
|---------|-----|------|-------------|
| `[tool.svci.environment]` | *any* | string | Environment variables set in the service |
| `[tool.svci.systemd]` | `restart` | string | Restart policy (default: `"on-failure"`) |
| `[tool.svci.systemd]` | `restart_sec` | integer | Seconds between restarts (default: `5`) |
| `[tool.svci.launchd]` | `run_at_load` | boolean | Start at login/boot (default: `true`) |

## Configuration

svci looks for config files in:

- `~/.config/svci/config.toml`

Custom templates can be placed at:

- `~/.config/svci/templates/systemd.service-template`
- `~/.config/svci/templates/launchd.plist-template`

All CLI options can also be set via environment variables with the `SVCI_` prefix (e.g., `SVCI_WORKING_DIR`, `SVCI_RUN_CMD`).

### Priority order

CLI args > environment variables (`SVCI_*`) > `--pyproject` (`[tool.svci]`) > config file (`~/.config/svci/config.toml`) > defaults

## Service modes

| Mode | Linux | macOS |
|------|-------|-------|
| `user` | systemd user unit (`~/.config/systemd/user/`) | LaunchAgent (`~/Library/LaunchAgents/`) |
| `system` | systemd system unit (`/etc/systemd/system/`) | LaunchDaemon (`/Library/LaunchDaemons/`) |
| `system-at-user` | `name@.service` template | LaunchDaemon with `UserName` |

## License

MIT
