Repository navigation
Rust control plane, desktop app, and release pipeline - #2
Conversation
Port the FastAPI control plane to Rust (axum + rusqlite) and ship it as
both a server binary and a native desktop app.
rust/
Feature-complete port of the Python implementation: identical HTTP API,
SQLite schema and scrypt parameters, so existing databases and worker
credentials keep working and splat-agent needs no changes. The SPA is
compiled into the binary with rust-embed, making a single self-contained
artifact. 30 integration tests: 8 ported from tests/test_api.py and 22
covering behaviour the Python suite never exercised (lease expiry,
delete/result conflicts, agent-ID ownership, revocation cascades,
dispatch ordering, claim idempotency, crash recovery).
Two deliberate fixes over the original: routing rejections now use the
{"detail": ...} envelope instead of an empty body, and the "no work
available" claim path commits its agent-idle update, which the Python
version discarded by returning from inside its connection context
manager.
desktop/
Tauri v2 shell that depends on rust/ as a path dependency, so there is
one implementation of the control plane. It binds the server to a
loopback port chosen by the OS and points a webview at it; external
links open in the system browser.
static/
Extract the brand mark to logo.svg, wire it up as the favicon, and add
a GitHub link to the header using the same mark and acid green. Rebuild
the credential dialog around a tabbed config panel (JSON, environment,
Docker) with a relabel action, backed by a new
PATCH /api/settings/keys/{access_key} endpoint.
.github/
CI runs fmt, clippy and tests plus a desktop compile check on Linux,
macOS and Windows. The release workflow builds desktop bundles (deb,
rpm, AppImage, msi, nsis, dmg) and standalone server archives across
five runners, publishing only once every job succeeds.
`disk_usage` was guarded by `cfg(unix)`, so the Windows build both failed clippy on the unused `path` argument and would have reported zero free space in the health endpoint and the SPA storage readout. Implement it with `GetDiskFreeSpaceExW` and make `libc` a unix-only dependency so Windows no longer pulls it in.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6c20194009
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if field.name() == Some("result_file") { | ||
| outcome = | ||
| Some(save_field(&mut field, &destination, state.settings.max_result_bytes).await?); |
There was a problem hiding this comment.
Renew the lease while streaming result uploads
When a result upload takes longer than SPLAT_AGENT_LEASE_SECONDS (60 seconds by default), save_field awaits the entire stream without renewing the job lease. The SPA polls /api/health, which runs expire_stale_agents, so a large or slow PLY upload can fail the job and mark its agent offline mid-request; the later unconditional update_remote_job then changes the same job back to completed while leaving the agent offline. Renew the lease during streaming or make the completion update conditional on the job still being active.
Useful? React with 👍 / 👎.
| json: { | ||
| instruction: "Save this as splat-agent.json beside the agent, or merge it into your existing config.", | ||
| lines: ({ name, url, access, secret }) => [ | ||
| [token("{", "code-punct")], | ||
| [token(" // " + name, "code-comment")], |
There was a problem hiding this comment.
Emit the agent's actual configuration format
When a user follows the new JSON-config tab, it tells them to save splat-agent.json, although the checked-in agent setup contract in README.md uses ~/.config/splat-agent/config.toml; moreover, the generated text contains a // comment and therefore is not valid JSON. The copied one-time secret consequently cannot configure the documented agent, and closing the dialog loses it, so this panel should emit the supported TOML format or direct the user through splat-agent init.
Useful? React with 👍 / 👎.
| if let Some(error) = &update.error { | ||
| values.push(("error", SqlValue::Text(error.clone()))); | ||
| } | ||
| if let Some(width) = update.width { | ||
| values.push(("width", SqlValue::Integer(width))); |
There was a problem hiding this comment.
Restore bounds checks for agent metadata
When an authenticated but buggy or compromised worker reports status, these values are persisted without the constraints enforced by the existing FastAPI API: error can exceed 2,000 characters, dimensions can be zero or negative, and fps/duration_seconds can be negative. This breaks the promised API parity and permits invalid or arbitrarily large metadata in SQLite; validate all optional fields before constructing the update.
Useful? React with 👍 / 👎.
Ports the FastAPI control plane to Rust (axum + rusqlite), ships it as a native desktop app via Tauri, and adds cross-platform release automation.
Control plane (
rust/)Feature-complete port: identical HTTP API, SQLite schema and scrypt parameters, so existing databases and worker credentials keep working and
splat-agentneeds no changes. The SPA is embedded withrust-embed, making a single self-contained binary.30 integration tests — 8 ported from
tests/test_api.py, 22 covering behaviour the Python suite never exercised (lease expiry, delete/result conflicts, agent-ID ownership, revocation cascades, dispatch ordering, claim idempotency, crash recovery).Two deliberate fixes over the original:
{"detail": ...}envelope instead of an empty body.Desktop app (
desktop/)Tauri v2 shell depending on
rust/as a path dependency, so there is one implementation. Binds the server to an OS-assigned loopback port and points a webview at it; external links open in the system browser.UI
Brand mark extracted to
logo.svgand wired up as the favicon; GitHub link added to the header using the same mark and acid green. Credential dialog rebuilt around a tabbed config panel (JSON / environment / Docker) with a relabel action, backed by a newPATCH /api/settings/keys/{access_key}endpoint.CI
ci.ymlruns fmt, clippy and tests plus a desktop compile check on Linux, macOS and Windows.release.ymlbuilds desktop bundles (deb, rpm, AppImage, msi, nsis, dmg) and standalone server archives across five runners, publishing only once every job succeeds.