Workstation orchestration for on-site programming contests.
Warning
Natsume is not yet battle-tested in real contests. Validate the complete workflow in your target environment before relying on it for a live event.
Natsume connects a contest roster, physical seats, managed Ubuntu workstations, and DOMjudge through one operator panel. Prepare the roster, enroll devices, bind them to seats, and manage the waiting screen and contest desktop from a central Server.
Feature gallery · Acknowledgements · Architecture · Documentation · Development
- Make contest-day operations manageable. Support a single on-site contest, with a design target of approximately 500–600 workstations per Server.
- Keep roster and workstation assignments consistent. Connect schools, teams, DOMjudge accounts, seats, and devices without hand-configuring each contestant desktop.
- Converge on the intended state. Reconcile Server targets with device reports, including after reconnects and process restarts. A submitted target is not proof that a workstation has applied it.
- Keep privileged operations narrow. Separate operator access, device identity, credential handling, desktop presentation, and root capabilities. Fail closed when identity or trust cannot be established.
Natsume is not a judging system or a general-purpose remote administration tool. DOMjudge remains the judging platform. Multi-contest hosting, Server HA, arbitrary remote shells, and file management are outside the project scope.
- Contest preparation: drag-and-drop XLSX roster import, a redacted change preview before commit, bilingual team and school metadata, school-logo checks, and DOMjudge ZIP export. Exports contain account passwords and must be handled as sensitive files; the panel does not display those passwords.
- Enrollment and device lifecycle: an explicit enrollment window for automatic approval, manual review when closed, and independent Enabled, Disabled, and Revoked filters for ongoing fleet management.
- Seats and accounts: seat-to-device binding, quick identification of unbound seats, row-level state colors, and account searches by username, seat, Chinese or English team name, and school.
- Session, Home, and power control: show the waiting screen or contest desktop, terminate contest sessions, reset contestant Home data, and request confirmed shutdown of online enabled devices. Bulk submissions expose per-device acceptance or rejection; shutdown requests expire after 60 seconds.
- Live readiness: automatically refreshed views of connection state and Gateway, Binding, Runtime, Session, and Home convergence, with refresh indicators on the Devices, Seats, and Targets pages.
- Contestant experience: a native GNOME Wayland waiting screen with team, school, seat, and offline information; a separate full GNOME contest desktop; and a local HTTPS gateway for DOMjudge automatic login.
The Web screenshots below show the actual panel with synthetic API fixtures, not a live contest. Seat setup and Waiting are native Slint UI previews with sample data. These illustrate the interface, not deployment or scale acceptance. Click any image to view it at full resolution.
Special thanks to my good friend @Runa798 for generously covering the project's LLM costs and supporting its development.
The architecture document is the sole manually maintained architecture authority. This is an orientation guide; the architecture describes the target state, and completion must be checked against code and acceptance evidence.
| Component | Location | Responsibility |
|---|---|---|
| Server | server/ |
Rust, Axum, and SQLite/Diesel; owns committed contest data, operator sessions, enrollment, bindings, credentials, and desired state. Serves HTTPS APIs, device WSS, and the production Web panel. |
| Operator panel | web/ |
React, TypeScript, and shadcn/ui; reads the generated OpenAPI contract and exposes administrator and viewer workflows. |
| Device Daemon | client/device-daemon/ |
Owns workstation identity, the authenticated control connection, local state reconciliation, and Caddy configuration. |
| Privileged Helper | client/privileged-helper/ |
Provides a closed set of privileged system operations over typed D-Bus; has no network role or arbitrary command interface. |
| Session Agent | client/session-agent/ |
Renders Waiting and seat-binding UI with Slint/Skia inside the GNOME Kiosk Wayland session. |
| Shared contracts | crates/ |
Device Control Protobuf, typed local D-Bus interfaces, and the shared XLSX roster contract. |
| Packaging and image integration | packaging/ |
Server/Client Debian packages, verified Caddy inputs, service integration, and the image-builder handoff. |
The panel talks to Server over HTTPS. Device Daemons use authenticated WSS with Protobuf and reconcile complete desired state, rather than consuming a remote command queue. On each workstation, the Daemon coordinates the Helper and Agent through typed local IPC. Caddy provides the loopback HTTPS path to DOMjudge; the Agent does not contact Server or receive account credentials.
Most operational and product documents are currently written in Chinese.
| Document | Start here when you need to… |
|---|---|
| Documentation index | Find maintained guides and release notes. |
| Architecture | Understand ownership, protocols, trust boundaries, data models, and verification requirements. |
| Deployment and operations | Provision TLS, bootstrap Server, install Client, and plan backup or recovery. |
| Image integration requirements and acceptance criteria | Configure the workstation image and verify Session, Home, display, and input behavior. |
| Packaging and image-builder handoff | Build Debian artifacts or integrate Client into an Ubuntu image. |
| Server guide, Web guide, and roster contract | Work on a specific application surface or the XLSX format. |
| Issue workflow | Track requirements and changes in GitHub Issues. |
Warning
The Server has undergone a human audit. Client development was AI-led, primarily using GPT-6 Astra, and the Client has not undergone a complete human audit. Its architecture and design still have shortcomings and need further human review and refinement.
Use Linux; Ubuntu 24.04 is the deployment baseline. Install Git, rustup, Node.js 24.1.0, pnpm 11.x, just, and prek 0.5.0. The repository pins Rust 1.97.1 in rust-toolchain.toml. On Ubuntu, the workspace's native build and test prerequisites include:
sudo apt-get install --yes build-essential pkg-config dbus-daemon \
libfontconfig1-dev libgl1-mesa-dev libudev-devFrom the repository root:
rustup show # Install/select the repository toolchain
cargo install cargo-deny --version 0.20.2 --locked
just toolchain # Check the pinned toolchain and manifests
just install # Install Node dependencies from the lockfile
prek install # Enable this checkout's pre-commit hookpnpm --filter @natsume/web dev --host 127.0.0.1Open the local URL printed by Vite. Its /api proxy expects an already configured Server at https://127.0.0.1:8443; the UI does not provide a built-in demo login. For a working local backend, follow the Server guide and deployment runbook to provision configuration, TLS/CA material, and an initial operator. Server modes read the fixed /etc/natsume-server/config.toml, not command-line configuration flags.
For UI-only work, the Playwright suite uses intercepted API fixtures and needs no running Server:
pnpm --filter @natsume/web exec playwright install --with-deps chromium
pnpm --filter @natsume/web e2ecargo build --workspace --locked
pnpm --filter @natsume/web build
prek run --all-filesprek is the single pre-commit check entry point. It runs dependency policy, Web Prettier and ESLint, Rust Clippy, and Rust/Web tests without automatically editing or staging files. CI adds further contract, browser, and packaging checks.
When changing the HTTP API, run just api and include the regenerated OpenAPI and TypeScript snapshots. Do not edit generated contracts by hand. Exact dependencies belong to lockfiles; package inputs and release procedures belong to packaging/. Running the full Client requires the provisioned GNOME dual-session image, not just a development build.








