Operate
Updates, backups and finding faults
Update notices are strictly separated from applying updates, running state is judged by the health check, and any restore is built on a backup you can verify.
Updates
It tells you, it does not update itself
When the console finds a new version it shows nothing more than a small marker. The update runs only after an administrator clicks it, reads the release notes and confirms — there is no background download and no automatic switch.
Run the install command again. It downloads the matching archive, verifies SHA-256, backs up the database and running files, switches, restarts and health-checks.
The backend runs the full release flow and restores the previous version if the probe fails. Older builds that show the button without a backend updater cannot self-update.
Containers are recreated by your orchestrator; from source you check out and rebuild both halves. Neither replaces a bare binary inside the running process.
Download acceleration
When GitHub is slow to reach directly, the "Version and updates" page offers public mirror routes. Auto measures the direct connection and each mirror and picks one, preferring the direct route when it works; you can also pin a mirror or force direct. Acceleration applies to the package only — the checksum manifest is always fetched directly, version checks go through the GitHub API without a mirror, and SHA-256 is still verified byte for byte before installing. Any route that fails falls back to a direct download.
# upgrading with the install script is the same command as installing
curl -fsSL https://raw.githubusercontent.com/SuInk/Diana/main/scripts/install.sh | sudo sh
Make sure the data and backup directories have room. If the database is being written to heavily, keep WAL/SHM alongside the backup, or take a consistent snapshot through the application's own backup flow first.
launchd's KeepAlive and systemd's Restart= bring the service straight back up after it exits. Once the updater notices it is supervised, it stops starting a new instance itself and instead asks the manager to restart it after the files are swapped (launchctl kickstart -k or systemctl restart). The manager then stops the old and starts the new in sequence, so two instances never fight over the same port and the later one does not die with address already in use. The install script writes DIANA_SERVICE_MANAGER, DIANA_SERVICE_LABEL and DIANA_SERVICE_DOMAIN into the service environment; a hand-rolled deployment can set them itself, or set DIANA_SERVICE_MANAGER=none to let the updater handle its own restart.
Day to day
Health checks, logs and backups
GET /api/healthNo login required; use it for process and orchestration probes.GET /api/auth/statusConfirms the admin session and whether this is a first start.GET /api/events/streamThe frontend should fall back to polling when SSE drops.logs/Service output and startup failures.logs/diana.logFilterable and downloadable from the console.data/diana.dbThe main store for configuration, messages, memory, tasks and audit.Temporary update backups are limited to the current attempt: old backups are removed before creating a new one, and the current backup is deleted after a successful health check. Failed updates and installations that skip startup retain their backup. Source updates remove temporary backups after a successful build and file replacement; a manual restart is still required. Cleanup failures are logged. The schedule below concerns separately managed data backups, which are not automatically deleted.
A backup schedule worth following
| Scope | Frequency | Retention |
|---|---|---|
| Consistent SQLite snapshot | Daily, and before every update | At least 7 daily and 4 weekly copies. |
| Runtime configuration and secrets | After every configuration change | Stored encrypted, with read access restricted. |
| Historical media | As the workload requires | Balance capacity eviction against privacy retention. |
| Restore drill | Monthly | Record how long it took and anything that was missing. |
Troubleshooting
Read the event reason first, the model chain second
The bot is online but silent in a group
Read the deterministic reason from the event detail: group enabled, reply window, muted account, member level, bot suppression, explicit mention, trigger word and the unprompted-reply result. Then turn on debug mode and check the context and structured judgement the model actually received.
Quoting the bot and mentioning it still gets ignored
The running version must include the routing rule where an explicit mention outranks a quote. The OneBot event should carry an at segment; the backend detects the explicit mention first, and only a quote without a mention goes to semantic evaluation.
The vision model cannot read a screenshot or small text
Confirm the vision role is bound to a model you tested with a real image, that the original was not downscaled, and that the image was not dropped by the token budget. Text-heavy images should use both OCR and the original as evidence.
Group management shows not found, or groups are missing
Check the OneBot connection and the get_group_list response. While connected it should list every group the bot has joined; it falls back to local configuration only when the connection is unavailable.
Unprompted-reply candidates stay pending forever
Candidates should go straight to semantic evaluation and write a definite result within 60 seconds. Getting stuck usually means the intent model timed out, the queue consumer is not running, or the running version predates the current logic.
The health check fails after an update
Check for a port conflict, database permissions, the frontend directory and the binary architecture. Installer backups live in .installer/backups; console update backups live in .diana-updates.
Development
Local checks and the CI bar
# Go and formatting
gofmt -l .
git diff --check
go test ./...
# production frontend build
cd frontend-next
npm ci
npm run build
# preview the docs (the site uses clean URLs, so the server must support them)
cd ..
npx serve docs
CI covers Linux amd64/arm64, Darwin amd64/arm64, Windows amd64 and Docker. Releases are tagged from the merged default branch and provide only full platform archives, SHA256SUMS and the update manifest latest.json, not standalone binaries. Release notes must state what changed, any compatibility impact, how it was verified and anything to watch when upgrading.
GitHub Pages
The site lives in docs/ with no build step. When the docs or the install script change on the default branch, GitHub Actions uploads the static artifact and deploys Pages. Pages link to each other without a file extension (/deploy rather than /deploy.html) and GitHub Pages resolves those to the matching .html; a local preview needs a server that does the same, as python3 -m http.server returns 404 for them.