# Capability: systemd

Gestionar units systemd local y remoto via SSH. Cubre: generar texto de unit files (`systemd_generate_unit`, pura), instalar+enable+start (`systemd_install`, `install_systemd_service`), restart/status (`systemd_restart`, `systemd_status`, `services_status`), y auditoria de apps con tag `service`.

## Funciones

| ID | Firma | Que hace |
|---|---|---|
| `install_systemd_service_bash_pipelines` | `install_systemd_service --name <N> --exec <PATH> [opts] -> json` | Pipeline que registra una app como servicio systemd del sistema: genera el unit, lo instala en /etc/systemd/system/, hace daemon-reload, enable, start y devuelve status. Requiere sudo sin password para systemctl y escritura en /etc/systemd/system/. |
| `services_status_go_infra` | `func ServicesStatus(registryRoot string) ([]ServiceStatus, error)` | Lista todas las apps registradas con tag 'service' y reporta su estado: unidad systemd activa, puerto escuchando, y pc_id local. |
| `setup_vps_app_go_infra` | `func SetupVPSApp(conn SSHConn, cfg DeployConfig) error` | Orquesta el setup inicial de una app en un VPS remoto: verifica SSH, crea dirs y usuario, sube binario, instala systemd unit y hace health check. |
| `systemd_generate_unit_go_infra` | `func SystemdGenerateUnit(name, execStart, workDir, user string, env map[string]string) string` | Genera el texto de un archivo .service de systemd para una app. Incluye restart automático y env vars en orden determinista. |
| `systemd_install_go_infra` | `func SystemdInstall(conn SSHConn, unitName, unitContent string) error` | Sube un unit file al host remoto, hace daemon-reload, enable y restart. Idempotente: reemplaza si el unit ya existe. |
| `systemd_local_enable_bash_infra` | `systemd_local_enable(name: string) -> json` | Habilita un servicio systemd local con systemctl enable para que arranque automáticamente al boot. Requiere sudo. |
| `systemd_local_install_unit_bash_infra` | `systemd_local_install_unit(name: string, unit_content: string) -> json` | Instala un unit file de systemd en /etc/systemd/system/<name>.service y ejecuta daemon-reload. Requiere sudo sin password para install y systemctl. Sobrescribe si el unit ya existe. |
| `systemd_local_restart_bash_infra` | `systemd_local_restart(name: string) -> json` | Reinicia un servicio systemd local con systemctl restart. Útil tras actualizar el binario o cambiar el unit. Requiere sudo. |
| `systemd_local_start_bash_infra` | `systemd_local_start(name: string) -> json` | Arranca un servicio systemd local con systemctl start. Devuelve el MainPID asignado. Requiere sudo. |
| `systemd_local_status_bash_infra` | `systemd_local_status(name: string, log_lines: int = 10) -> json` | Devuelve el estado de un servicio systemd local: active state, sub state, PID, enabled, y las N últimas líneas de journalctl. No requiere sudo. |
| `systemd_local_uninstall_bash_infra` | `systemd_local_uninstall(name: string) -> json` | Detiene, deshabilita y elimina el unit file de un servicio systemd local. Idempotente: no falla si el servicio ya está parado o el unit no existe. Requiere sudo. |
| `systemd_restart_go_infra` | `func SystemdRestart(conn SSHConn, unitName string) error` | Reinicia un servicio systemd en un host remoto via SSH. |
| `systemd_status_go_infra` | `func SystemdStatus(conn SSHConn, unitName string, logLines int) (SystemdServiceStatus, error)` | Consulta el estado de un servicio systemd en un host remoto. Retorna estado activo, sub-estado, PID y logs recientes. |
| `tail_journal_bash_infra` | `tail_journal(unit: string, lines: int=100, follow: bool=false, since: string="", priority: string="info") -> void` | Wrapper sobre journalctl con formato consistente. Tail logs de una unidad systemd con coloreado, filtro por prioridad y seguimiento opcional. |


## Ejemplo canonico

### Service local (requiere sudo)

```bash
./fn run install_systemd_service \
  --name myapp \
  --exec /opt/myapp/myapp \
  --workdir /opt/myapp \
  --user www-data \
  --env "PORT=8080" \
  --env "DB_PATH=/var/lib/myapp/db"
```

### Service remoto via SSH

```bash
# 1. Generar unit (pure, sin side effects)
unit=$(./fn run systemd_generate_unit \
  --name myapp \
  --exec-start "/opt/myapp/myapp" \
  --work-dir /opt/myapp \
  --user deploy \
  --env "PORT=8080")

# 2. Instalar remoto
./fn run systemd_install --host organic-machine --unit-name myapp --content "$unit"

# 3. Status
./fn run systemd_status --host organic-machine --unit myapp.service
```

### Auditoria de todos los services

```bash
./fn doctor services --json | jq '.[] | {id, active, port_listening}'
```

## Fronteras

- **NO maneja timers ni paths units**. Solo service units. Para cron/timer usa dag_engine (`apps/dag_engine/`, `schedule:` en el YAML del DAG) o cron clasico.
- **NO genera socket activation**. Asume que la app abre su propio puerto.
- **NO instala unit a nivel usuario (`--user`)** salvo que el caller pase la flag al systemctl. Default es `/etc/systemd/system/`.
- Apps en `apps/` que se ejecutan local pero NO son service de larga duracion: NO necesitan systemd. Solo apps con `tags: [service]` en su `app.md`.
