Docs menu

Operations

The commands on this page run from your project folder. Every docker compose command takes -f deploy/docker-compose.yml.

Applying changes

After you change config/config.yaml, .env, package.json, or anything in src/, rebuild and restart:

docker compose -f deploy/docker-compose.yml up -d --build

Changes to files in docs/ are picked up at the next sync.

Upgrades

The engine is the deskhand npm package. Your config, docs, and code stay as they are.

npm install deskhand@latest
docker compose -f deploy/docker-compose.yml up -d --build

Commit package.json and package-lock.json; the Docker build installs from the lockfile.

Read the release notes for new or changed config keys. An invalid config stops startup with the path of the bad key, so problems show up right away in the logs.

Data volume

Everything Deskhand stores lives in the data Docker volume, mounted at /app/data. When you run npm start or npm run console, it uses the data/ folder in your project instead.

To run the console against the data volume, stop the service first:

docker compose -f deploy/docker-compose.yml stop
docker compose -f deploy/docker-compose.yml run --rm deskhand node --no-warnings=ExperimentalWarning src/main.ts --console
FileContents
session.sqliteConversations, thread mappings, and approvals.
docs.sqliteThe search index and per-source sync status.
deskhand.lockThe instance lock.

docs.sqlite can be rebuilt from your sources: stop Deskhand, delete it, and start again.

docker compose -f deploy/docker-compose.yml stop
docker compose -f deploy/docker-compose.yml run --rm deskhand rm /app/data/docs.sqlite
docker compose -f deploy/docker-compose.yml start

Don’t delete session.sqlite unless you want to drop every conversation and pending approval.

Single instance

Deskhand holds an exclusive lock on deskhand.lock while it runs. A second Deskhand on the same data, in the same container or another, refuses to start under the header Deskhand cannot start: with another Deskhand is already using /app/data/, the absolute path of the data folder. The lock is released when the process exits, however it exits. Stop the service before using docker compose run on the same volume.

Don’t scale the service to more than one replica.

Restarts

Compose runs the service with restart: unless-stopped. If Deskhand hits a fatal error it exits with status 1 and Compose starts it again. Answers and approvals that were in progress resume from the data volume. Messages sent while it was stopped are not answered.

docker compose -f deploy/docker-compose.yml logs -f
docker compose -f deploy/docker-compose.yml restart

Logs

LineMeaning
[deskhand] up: slack, teamsConnected to these platforms.
[docs] <source>: N indexed, N removed, N failedA source finished syncing.
[docs] removed N documents of sources no longer configuredA source was removed from the config, and its documents were deleted.
[turn] unanswered <reason> <detail>The model could not answer. The person sees Sorry, I could not answer that (<reason>).
[approvals] <id> <user>: <text>A click on an approval card that did not count, and the reply it got.
[mcp] <server>: skipping tool ...An MCP tool name collided with another tool.

Backups

Your project folder is in git, except .env and secrets/. Back those up with the data volume: stop Deskhand, copy the volume out of the container, and archive it.

docker compose -f deploy/docker-compose.yml stop
docker compose -f deploy/docker-compose.yml cp deskhand:/app/data ./deskhand-data
tar czf deskhand-backup.tgz deskhand-data .env secrets
docker compose -f deploy/docker-compose.yml start

Leave out secrets if you have no service account key.