Skip to content

Rust control plane, desktop app, and release pipeline - #2

Merged
NaveDanan merged 2 commits into
mainfrom
feat/rust-port-desktop
Aug 6, 2026
Merged

NaveDanan merged 2 commits into
mainfrom
feat/rust-port-desktop

Conversation

@NaveDanan

Copy link
Copy Markdown
Contributor

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-agent needs no changes. The SPA is embedded with rust-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:

  • Routing rejections now use the {"detail": ...} envelope instead of an empty body.
  • 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 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.svg and 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 new PATCH /api/settings/keys/{access_key} endpoint.

CI

ci.yml runs fmt, clippy and tests plus a desktop compile check on Linux, macOS and Windows. release.yml builds desktop bundles (deb, rpm, AppImage, msi, nsis, dmg) and standalone server archives across five runners, publishing only once every job succeeds.

Note: the agent config field names shown in the credential dialog (SPLAT_SERVER_URL etc.) are inferred from the API and should be checked against the splatlab-agent repo.

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.
@NaveDanan
NaveDanan merged commit e1428d7 into main Aug 6, 2026
12 checks passed
@NaveDanan
NaveDanan deleted the feat/rust-port-desktop branch August 6, 2026 06:51

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread rust/src/routes/agents.rs
Comment on lines +454 to +456
if field.name() == Some("result_file") {
outcome =
Some(save_field(&mut field, &destination, state.settings.max_result_bytes).await?);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment thread rust/static/app.js
Comment on lines +269 to +273
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")],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment thread rust/src/routes/agents.rs
Comment on lines +358 to +362
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)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant