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 | File | Contents |
|---|---|
session.sqlite | Conversations, thread mappings, and approvals. |
docs.sqlite | The search index and per-source sync status. |
deskhand.lock | The 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
| Line | Meaning |
|---|---|
[deskhand] up: slack, teams | Connected to these platforms. |
[docs] <source>: N indexed, N removed, N failed | A source finished syncing. |
[docs] removed N documents of sources no longer configured | A 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.