Skip to content

From systemd

runwisp import systemd converts .service units into runwisp.toml. A Type=oneshot unit becomes a task that runs when the daemon starts. Any other unit becomes a service.

Terminal window
runwisp import systemd /etc/systemd/system/myapp.service -o runwisp.toml
runwisp validate

Given tempoledger.service:

[Unit]
Description=Tempo Ledger API
[Service]
Type=simple
ExecStart=/usr/local/bin/bun run start
WorkingDirectory=/srv/tempoledger
User=deploy
Group=deploy
Environment=NODE_ENV=production
Environment=PORT=3000
Restart=always
TimeoutStopSec=30
KillSignal=SIGTERM
[Install]
WantedBy=multi-user.target

you get:

[services.tempoledger]
description = "Tempo Ledger API"
run = "/usr/local/bin/bun run start"
working_dir = "/srv/tempoledger"
graceful_stop = "30s"
stop_signal = "SIGTERM"
user = "deploy:deploy"
[services.tempoledger.env]
NODE_ENV = "production"
PORT = "3000"

The name comes from the file name. A piped-in unit has no file name, so it gets a placeholder name and a note to rename it. A summary on stderr lists every unit and anything that needs a look.

If you already have a runwisp.toml, use --write instead of -o; see Staging and promoting. All flags are in the CLI reference.

The import doesn’t stop or disable anything. If systemd and RunWisp both run the same process, you get two copies fighting over ports or queues. Disable the unit before starting it under RunWisp:

Terminal window
sudo systemctl disable --now myapp.service

--now stops it immediately; disable keeps it from starting on boot. You can move a few units at a time; just never leave one enabled in both. There is no takeover for systemd units.

systemd runwisp.toml Notes
Type=oneshot [tasks.NAME] with run_on_start = "boot" Runs once per boot.
any other Type [services.NAME] See Restart= below.
ExecStart run One command. @ - + ! prefixes are removed, with a note.
WorkingDirectory working_dir
User (+ Group) user Combined as user:group. The daemon must run as root to switch users.
Environment env Every line is kept.
EnvironmentFile env_file Only the first file; a leading - is dropped.
TimeoutStopSec graceful_stop
KillSignal stop_signal
[Unit] Description description
[Install] (not needed) Services start with the daemon. See below.

RunWisp starts services when the daemon starts. To keep one stopped at boot, set autostart = false. For start order, use depends_on.

Anything that can’t be mapped gets a # TODO in the TOML and a note on the unit’s row.

  • Restart=. Imported services use RunWisp’s default restart, which restarts after any exit. For Restart=on-failure, set restart = "on_failure". A unit with Restart=no (or none) gets a note: if it should run once, make it a task.
  • More than one command. RunWisp runs one run command. Only the first ExecStart is imported; other ExecStart, ExecStartPre, ExecStartPost, and ExecStop lines are flagged. Put them into the run script, or setup steps into a separate task.
  • Type=notify and Type=forking. RunWisp watches the process it starts and treats it as up at once. Run the program in the foreground if you can.
  • Sandboxing. ProtectSystem, PrivateTmp, NoNewPrivileges, CapabilityBoundingSet, and similar directives are dropped. The process gets more access than the unit allowed. If that matters, use a container or a restricted user.
  • Socket activation. Not supported. The program must open its own port.
  • Template units. %i, %I, %n, and similar are not filled in. Replace them in the run line.