Metadata-Version: 2.4
Name: svci
Version: 1.1.0
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"
```

### 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
