Skip to main content
Version: 2.5.0

service management

kasmos ships service unit files in contrib/ for both linux (systemd) and macos (launchd). they keep the orchestration daemon and the remote task store running persistently across reboots without requiring a dedicated shell session.

service units

unitbinarypurpose
kasmoskas daemon start --foregroundorchestration daemon — claims signals and advances plan lifecycle
kasmosdbkas serveremote task store http server on port 7433

linux (systemd)

both units run under your user account (systemctl --user) and require an absolute path to the kas binary. the contrib/*.service files are templates — the __KAS_BIN__ placeholder must be substituted before enabling a unit.

preferred workflow (just)

# install and start both services
just services-enable

# orchestration daemon only
just kasmosd-enable

# task store server only
just db-service-enable

each just recipe resolves the kas binary via command -v kas, renders the .service template with the absolute path, writes the result to ~/.config/systemd/user/, runs systemctl --user daemon-reload, and enables + starts the unit.

manual installation

if you do not have just installed:

mkdir -p ~/.config/systemd/user

# orchestration daemon
sed "s|__KAS_BIN__|$(command -v kas)|g" \
contrib/kasmos.service \
> ~/.config/systemd/user/kasmos.service
systemctl --user daemon-reload
systemctl --user enable --now kasmos

# task store
sed "s|__KAS_BIN__|$(command -v kas)|g" \
contrib/kasmosdb.service \
> ~/.config/systemd/user/kasmosdb.service
systemctl --user daemon-reload
systemctl --user enable --now kasmosdb

checking service status

systemctl --user status kasmos
systemctl --user status kasmosdb

reading logs

journalctl --user -u kasmos # orchestration daemon logs
journalctl --user -u kasmosdb # task store logs
journalctl --user -u kasmos -f # follow live output
journalctl --user -u kasmos --since "1 hour ago"

stopping and disabling

systemctl --user stop kasmos
systemctl --user disable kasmos

systemctl --user stop kasmosdb
systemctl --user disable kasmosdb

service file contents

contrib/kasmos.service (template — __KAS_BIN__ is substituted by just kasmosd-install):

[Unit]
Description=kasmos orchestration daemon
After=network.target

[Service]
Type=simple
ExecStart=__KAS_BIN__ daemon start --foreground
ExecStop=__KAS_BIN__ daemon stop
Restart=on-failure
RestartSec=5
Environment=HOME=%h
StandardOutput=journal
StandardError=journal
SyslogIdentifier=kasmos

[Install]
WantedBy=default.target

installed unit example (with kas at /home/you/go/bin/kas):

ExecStart=/home/you/go/bin/kas daemon start --foreground
ExecStop=/home/you/go/bin/kas daemon stop

contrib/kasmosdb.service (template — __KAS_BIN__ is substituted by just db-service-install):

[Unit]
Description=kasmos plan store server
After=network.target

[Service]
Type=simple
ExecStart=__KAS_BIN__ serve
Restart=on-failure
RestartSec=5
Environment=HOME=%h

[Install]
WantedBy=default.target

both units use Restart=on-failure so they recover from crashes without manual intervention.


macos (launchd)

on macos, kasmos uses launchd plists in contrib/. plists are loaded per-user via launchctl and live in ~/Library/LaunchAgents/.

preferred workflow (just)

# install and load both agents
just services-enable

# orchestration daemon only
just kasmosd-enable

# task store server only
just db-service-enable

each just recipe renders the plist template with your $HOME and the path to the kas binary, copies it to ~/Library/LaunchAgents/, and calls launchctl load -w to load it immediately.

manual installation

mkdir -p ~/Library/LaunchAgents ~/Library/Logs/kasmos

# orchestration daemon
sed "s|__KAS_BIN__|$(command -v kas)|g; s|__HOME__|$HOME|g" \
contrib/com.kasmos.daemon.plist \
> ~/Library/LaunchAgents/com.kasmos.daemon.plist
launchctl load -w ~/Library/LaunchAgents/com.kasmos.daemon.plist

# task store
sed "s|__KAS_BIN__|$(command -v kas)|g; s|__HOME__|$HOME|g" \
contrib/com.kasmos.taskstore.plist \
> ~/Library/LaunchAgents/com.kasmos.taskstore.plist
launchctl load -w ~/Library/LaunchAgents/com.kasmos.taskstore.plist

checking service status

launchctl list | grep kasmos

look for com.kasmos.daemon and com.kasmos.taskstore. a pid in the first column means the service is running.

reading logs

tail -f ~/Library/Logs/kasmos/daemon.log # orchestration daemon logs
tail -f ~/Library/Logs/kasmos/taskstore.log # task store logs

stopping and unloading

# stop and unload
launchctl unload -w ~/Library/LaunchAgents/com.kasmos.daemon.plist
launchctl unload -w ~/Library/LaunchAgents/com.kasmos.taskstore.plist

# to also delete the plist files (permanent removal)
rm ~/Library/LaunchAgents/com.kasmos.daemon.plist
rm ~/Library/LaunchAgents/com.kasmos.taskstore.plist

plist template contents

contrib/com.kasmos.daemon.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.kasmos.daemon</string>
<key>ProgramArguments</key>
<array>
<string>__KAS_BIN__</string>
<string>daemon</string>
<string>start</string>
<string>--foreground</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>HOME</key>
<string>__HOME__</string>
</dict>
<key>StandardOutPath</key>
<string>__HOME__/Library/Logs/kasmos/daemon.log</string>
<key>StandardErrorPath</key>
<string>__HOME__/Library/Logs/kasmos/daemon.err.log</string>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

contrib/com.kasmos.taskstore.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.kasmos.taskstore</string>
<key>ProgramArguments</key>
<array>
<string>__KAS_BIN__</string>
<string>serve</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>HOME</key>
<string>__HOME__</string>
</dict>
<key>StandardOutPath</key>
<string>__HOME__/Library/Logs/kasmos/taskstore.log</string>
<key>StandardErrorPath</key>
<string>__HOME__/Library/Logs/kasmos/taskstore.err.log</string>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

launchd's KeepAlive=true setting is the equivalent of Restart=on-failure — launchd will restart the process if it exits.


running the daemon directly (without a service manager)

for debugging or one-shot runs, start the daemon in the foreground:

kas daemon start --foreground

or use just:

just kasmosd-start

check running daemon status:

kas daemon status

stop the daemon:

kas daemon stop
# or:
just kasmosd-stop

diagnosing installation

use the built-in doctor command to verify the daemon and task store are installed and responding:

just doctord

output example (linux):

== kasmos daemon doctor ==

binary:
/home/user/go/bin/kas

user units:
- kasmos.service: installed, enabled=enabled, active=active
- kasmosdb.service: installed, enabled=enabled, active=active

daemon api:
daemon socket present: /run/user/1000/kasmos/kas.sock

next steps:
- just kasmosd-enable # install + enable orchestration daemon
- just db-service-enable # install + enable plan store service
- just services-enable # enable both services
- just kasmosd-start # direct foreground/background daemon start

why the daemon matters for signals

when an agent emits mcp signal_create (or, as a fallback, kas signal emit ...), the signal is written as a pending row in the task store database. the orchestration daemon is what actually claims that row and advances the plan's lifecycle state (e.g. from implementingreviewing).

if you emit signals without a running daemon, signals accumulate as pending rows but plans do not advance. start the daemon — either via the service manager or kas daemon start --foreground — before running headless agent workflows that rely on signal-driven orchestration.