Run Kraft as a service
Kraft starts at login and starts again if it exits, and kraft admin health
shows it running. A second instance with its own home and port runs beside it.
Before you start
$KRAFT_HOMEis~/.kraftunless you set it; see Environment variables.- Run
kraft admin install-servicefrom a shell whereclaude,git,ghand your other tools are onPATH. The service takes itsPATHfrom that shell. - Kraft must not be running:
install-servicerefuses while a server is up.
Run Kraft as a service
A service starts Kraft at login and restarts it if it exits.
- Stop the running server:
kraft admin stop - Install the service:
kraft admin install-service
On macOS this writes a launchd agent and loads it. On Linux it writes a systemd user unit and enables it. It prints where it wrote the file:kraft: wrote /Users/you/Library/LaunchAgents/com.kraft.daemon.plist, loaded with launchctl
On Linux the line names~/.config/systemd/user/kraft.service(under$XDG_CONFIG_HOMEwhen you set it) andsystemctl --user. - Check the service, as Verify the service shows.
There is one service per user. Its launchd label and systemd unit name are fixed, so run a second instance by hand: see Run two instances.
Give the service an environment
install-service copies PATH and the variables that locate the instance from
the shell you ran it from, and writes them into the unit. The list is in
Environment variables.
To pick up a changed PATH later, run kraft admin uninstall-service, then
install-service again.
Nothing else from that shell reaches the service. A repo's
env_passthrough copies a variable from the
server's own environment, so under a service it finds only the ones install-service copied. A
key you export in your shell, such as GEMINI_API_KEY or a forge token, does
not reach the workers. Set it in the service instead, then run
kraft admin restart:
- systemd: run
systemctl --user edit kraftand add the variable to the drop-in it opens:[Service] Environment="GEMINI_API_KEY=..."
The drop-in is a separate file from the unit Kraft writes, so it survivesuninstall-serviceandinstall-service. - launchd: add it to the agent's
EnvironmentVariables:plutil -replace EnvironmentVariables.GEMINI_API_KEY -string "${GEMINI_API_KEY:?export GEMINI_API_KEY in this shell first}" \ ~/Library/LaunchAgents/com.kraft.daemon.plist-replaceadds the key or changes it, so it is safe to run again. With the variable unset or empty in your shell, the shell stops the command and prints that message, so an empty value never replaces the key already in the file.install-servicerewrites that file, so do this again after you reinstall the service.
Both files are usually readable by other accounts on the machine, and so is a
key written into them. On systemd, keep keys in a file only you can read, such
as ~/.config/kraft/secrets.env after chmod 600, and point the drop-in at
it with EnvironmentFile=%h/.config/kraft/secrets.env instead of
Environment=.
Verify the service
kraft admin restart
kraft admin health
restart goes through the service manager when a service is installed, and
prints:
kraft: restarted the service
health exits 0 once the server is back, and its version row names the
release it runs:
status ok
version 2.0.0
After an update and before the restart, health also prints the installed
release on an installed row that says restart pending. A 1.4 server shows no
such row: Upgrade from 1.4
says what to read instead.
Stop a service
kraft admin stop does not keep a service stopped: the service manager starts
it again. Where a guide says to stop the server and Kraft runs as a service,
remove the service instead, then put it back when you are done.
Before you remove it, save what you added to the service. uninstall-service
deletes the service file, and install-service writes a new one from your
shell:
- launchd: both commands replace the agent's plist, so every key you added to
its
EnvironmentVariableswithplutilis gone, a forge token or worker credentials included, and nothing says so. Beforeuninstall-service, runplutil -p ~/Library/LaunchAgents/com.kraft.daemon.plistand note the keys you added. Afterinstall-service, add them again, as Give the service an environment shows, then runkraft admin restart. - systemd: a drop-in is a separate file from the unit Kraft writes, so it survives. Only what you put in the unit file itself is lost.
Then remove the service:
kraft admin uninstall-service
kraft admin stop
uninstall-service does not wait for the server to finish, so kraft admin stop
follows it. It prints kraft: no server running, or kraft: stopped (pid N)
when the server was still draining: go on after either.
Do the task that needs the server stopped. Then put the service back:
kraft admin install-service
install-service takes the environment of the shell you run it from, as above.
Remove the service
Save what you added to the service first, as Stop a service says: removing a launchd agent deletes its file.
kraft admin uninstall-service
It stops the server, without waiting for it to finish, and deletes the launchd agent or the systemd unit. A systemd drop-in you made stays.
Run two instances
Two instances need separate homes and separate ports. A second server on the same port refuses to start and names the one already there.
- Start the second instance once on a free port. The first start seeds its
config/. This example uses 8767, since 8765 is the default and 8766 is where a contributor'sjust devruns:KRAFT_HOME=~/kraft-staging KRAFT_PORT=8767 kraft admin start --detach
You can also makeconfig/yourself before the first start, to write itsaccess.yamlor asandbox.yamlfirst. The first start then adds each default file the directory lacks, and keeps the files you wrote. - Write the port into that home's
access.yaml, so the server and thekraftcommand find it withoutKRAFT_PORT. A port given only asKRAFT_PORTor--portis not saved, and every other command would still dial 8765.
The command below adds the line only ifaccess.yamlhas noport:line yet. Kraft does not seedaccess.yaml, so a missing file counts as noport:line. A second run changes nothing. If the file already has aport:line, change its value to 8767 by hand: the command leaves it alone.f=~/kraft-staging/config/access.yaml grep -q '^port:' "$f" || printf '\nport: 8767\n' >> "$f" - Run every command for that instance with the same
KRAFT_HOME:KRAFT_HOME=~/kraft-staging kraft view list KRAFT_HOME=~/kraft-staging kraft admin stop - Start any agent you run yourself with the same
KRAFT_HOME. An agent reaches the instance its environment names. Workers inherit their instance'sKRAFT_HOME, so their ownkraftcalls reach the instance that started them.
You know it worked when step 1 prints the address with port 8767, and
KRAFT_HOME=~/kraft-staging kraft view list shows the second instance's board,
not the first's.
Next steps
- Back up and restore the database: copy the database before you change a service or a home
- Remote access: bind a service beyond loopback, with a password
- Environment variables: every variable that locates an instance