skiffd - solutionscay/skiff GitHub Wiki

skiffd is the Skiff daemon. It owns the pseudo-terminals (PTYs) and the processes for all sessions. The desktop app connects through a local Unix socket.

You can close the window and leave agents at work. When you open Skiff again, it connects to the same daemon.

Session lifetime

Action Result
Close or reload the window Sessions keep running in skiffd.
Open the window again Terminals show their current screen and available history.
An agent exits Its terminal returns to an interactive shell.
Restart skiffd Running sessions stop. Saved sessions return as new shells.
Reboot the computer Processes stop. Skiff restores the saved workspace when the daemon starts again.

The daemon keeps a terminal screen and up to 2,000 lines of scrollback per session in memory. A client first receives a snapshot, then live output.

Workspace restore

skiffd saves groups, layouts, session IDs, names, folders, terminal sizes, and themes in a workspace file. It saves after changes and on normal shutdown.

After a daemon restart, each saved session starts a shell in its folder with its previous ID. If the folder no longer exists, the shell starts in the home folder.

The workspace file does not save running processes, terminal screens, or scrollback. Agents do not resume automatically after a daemon restart.

Startup and updates

The app first tries to connect to the socket. If it cannot connect, it starts skiffd and tries again. skiff skipper does the same. A daemon that skiff skipper starts does not belong to the terminal or SSH login that started it. See Skiff agent.

The app finds the daemon binary in this order:

  1. The path in SKIFF_DAEMON, if set.
  2. A skiffd binary next to the app executable.
  3. skiffd on PATH.

Packages include the daemon. You do not need to start it separately for normal use.

skiffd has its own version, separate from the desktop app version. On connection, the app checks the daemon version and protocol number.

Daemon state App behavior
Same version and protocol Uses the daemon.
Older version that supports reload, and the bundled skiffd can adopt its sessions Moves the daemon onto the bundled skiffd in place, with no prompt. The daemon keeps its pid, and every session keeps running.
Older version or different protocol, with no live sessions Replaces the daemon automatically if it can identify and stop the process.
Older version or different protocol, with live sessions Shows a warning and a Restart skiffd button. A different protocol can cause parts of the app to fail.
Newer version with the same protocol Uses the daemon and shows a version warning.
Accepts connections but does not answer the handshake within two seconds Reports that the daemon does not respond.

Save your work before you select Restart skiffd. The restart stops running sessions. Panes return as shells in their folders.

Files and paths

File Release build Debug build
Socket <runtime dir>/skiff/skiffd.sock <runtime dir>/skiff/skiffd-dev.sock
Log, when the app starts the daemon Beside the socket: skiffd.log Beside the socket: skiffd-dev.log
Workspace <state dir>/skiff/workspace.json <state dir>/skiff/workspace-dev.json
Settings <config dir>/skiff/projects.toml Same default file as the release build
Watcher log and lock Beside the socket: skiffd.watch.log, skiffd.watch.lock skiffd-dev.watch.log, skiffd-dev.watch.lock
Start lock for skiff skipper Beside the socket: skiffd.start.lock skiffd-dev.start.lock

The runtime directory is the same from the desktop and from an SSH login:

  • On Linux, it is $XDG_RUNTIME_DIR. If that variable is not set, it is /run/user/<uid> when that folder exists.
  • On macOS, it is the per-user temporary folder that the desktop gets as $TMPDIR. An SSH login can lack $TMPDIR.
  • In all other cases, it is the system temporary directory.

On Linux, the default state directory is $XDG_STATE_HOME, or ~/.local/state if unset. The default config directory is $XDG_CONFIG_HOME, or ~/.config if unset.

On platforms without a state directory, Skiff uses the local data directory for the workspace. On macOS, the default workspace and settings files are under ~/Library/Application Support/skiff/.

When the app starts a new daemon, it moves the previous log to skiffd.log.1 or skiffd-dev.log.1. A daemon started directly writes logs to standard error.

Stop the daemon

Run skiff daemon stop. The daemon saves the workspace and ends every session. The command returns when the socket stops answering.

skiffd ignores SIGTERM and SIGINT from a process in one of its own sessions. It logs the sender's process ID and command line. A sender that exits before the daemon can check it counts as a process in a session. So a pkill skiffd in a pane cannot end the panes around it. From a pane, use skiff daemon stop.

A signal from outside the daemon's sessions stops the daemon as before. Examples are a logout, systemd, the app, or a shell outside Skiff. A reload installs the signal handlers again.

Environment variables

Set these variables before you start the app or daemon. An existing daemon keeps the environment from its startup.

Variable Purpose
SKIFF_DAEMON Selects the daemon binary that the app starts.
SKIFF_SOCKET Selects the Unix socket path. The app and daemon must use the same path.
SKIFF_STATE Selects the workspace file.
SKIFF_CONFIG Selects the projects.toml settings file.
SKIFF_LEDGER Selects the Skiff agent's ledger.db. Read by skiff ledger and skiff watch.
SKIFF_SHELL_ENV=0 Disables the login-shell environment and alias probe.
RUST_LOG Sets the daemon log filter, for example debug. The default is info.

At startup, the daemon probes the shell in SHELL as an interactive login shell. The probe reads environment variables and aliases.

If the daemon starts without TERM, it imports the shell environment. This gives desktop launches access to shell settings such as PATH and EDITOR. If TERM is set, it keeps the inherited environment and reads aliases only. The probe has a three-second timeout.

Development

From the repository root, build the daemon with:

cargo build -p skiffd

pnpm tauri dev also builds it before the app starts. Debug builds use a separate socket and workspace, so they can run beside the installed app. They share the default settings file.

A rebuild does not replace a running daemon. To use a new build:

  1. Save the work in the sessions that use the development daemon.
  2. Run skiff daemon reload to move the development daemon onto the new build. Every session keeps running.
  3. If the reload refuses, run skiff daemon stop. This ends every session of the development daemon.
  4. Restart or reload the development app.

pnpm tauri dev builds skiffd only when it starts. When the app rebuilds after that, target/debug/skiffd stays as it was. If that skiffd is no newer than the daemon that runs, the app keeps the daemon and shows no Restart skiffd button, because a restart would start the same old build. The app logs a line that names the binary and tells you to run cargo build -p skiffd. If the protocol is different, the app still shows the warning.

A debug skiff uses the development socket by default. Use --socket PATH to select a different daemon.

To run the debug daemon directly, use:

RUST_LOG=debug target/debug/skiffd

It stays in the foreground and prints logs to standard error. If another daemon already uses its socket, it exits with skiffd is already running. It removes a stale socket if it cannot connect to it.

Protocol changes

The app compares the daemon's protocol number with its own. skiff skipper refuses a daemon with an older protocol. Recent changes:

Protocol Change
25 A submit request types text and presses Enter in one step. skiffd refuses it when the person typed after the client's check. A turn_ended event marks the end of each turn.
26 skiffd marks the Skiff agent's session. A coordinator request finds that session or starts it under one lock. A request that creates a session cannot set the mark.

skiff daemon stop uses a shutdown request.

Source reference

  • Daemon: sessions, terminal screens, workspace restore, and socket server.
  • Shared types: protocol, paths, settings, and session model.
  • Client: requests and event subscriptions.
  • Desktop connection: startup, version checks, logs, and restart behavior.
⚠️ **GitHub.com Fallback** ⚠️