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.

Installed with the script

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.

Release update from the console

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.

Docker or source

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
Before updating

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.

When a service manager owns the process

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

Health checkGET /api/healthNo login required; use it for process and orchestration probes.
Login stateGET /api/auth/statusConfirms the admin session and whether this is a first start.
Live eventsGET /api/events/streamThe frontend should fall back to polling when SSE drops.
Install logslogs/Service output and startup failures.
Application loglogs/diana.logFilterable and downloadable from the console.
SQLitedata/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

ScopeFrequencyRetention
Consistent SQLite snapshotDaily, and before every updateAt least 7 daily and 4 weekly copies.
Runtime configuration and secretsAfter every configuration changeStored encrypted, with read access restricted.
Historical mediaAs the workload requiresBalance capacity eviction against privacy retention.
Restore drillMonthlyRecord 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.