galaxyproject / galaxyproject/loom

Orbit: remote control of local instances via Galaxy as relay (status, prompt, stop from any device)

Open
#74 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
14
Forks
12
Avg merge
6d 5h
Merged PRs (30d)
17

Description

## Idea

Allow remote monitoring and control of a locally-running Orbit instance via Galaxy as a relay. Use cases:

- Kicked off a long pipeline on the workstation, want to check status from a phone / laptop at a coffee shop.
- Collaborator wants to peek at the analysis state without screen-share.
- Trigger a follow-up action ("when alignment finishes, run multiqc") from another device.
- Pause/stop a runaway local job remotely.

The constraint that makes this interesting: Orbit is a local Electron app on a personal machine, not reachable from the public internet. Punching holes (ngrok-style tunnels, opening ports) is unfriendly and security-fraught. Galaxy already has the user's identity, persistent storage, and is reachable from anywhere — use it as the relay.

## Why Galaxy as relay

- **Auth and identity already solved** — only the user's own Galaxy account can post commands, no new auth surface.
- **Persistent** — survives Orbit restart, laptop suspend, etc.
- **Cross-device** — any browser logged into Galaxy can interact.
- **No inbound network on the local machine** — Orbit only ever makes outbound HTTPS to Galaxy.
- **Dovetails with #69** (stashing project context in Galaxy history) — same mechanism, broader purpose.

## Proposed shape

Per Orbit session, allocate a dedicated "control" history (or a hidden dataset collection within the project history). Two roles:

1. **Commands inbox** — datasets containing queued instructions written by remote clients.
2. **Events outbox** — datasets containing status snapshots, recent activity, log tails, written by Orbit.

### Local Orbit side

Background poller (10–30s interval) in main process:
- `GET /api/histories/{control_id}/contents?since={last_seen}` — fetch new command datasets.
- For each command: parse, dispatch (route to brain as a synthetic user message, or handle in-shell for control verbs like `status`, `stop`, `pause`).
- Write a result dataset back acknowledging the command.

Heartbeat: every N seconds, write/update an "alive" dataset with timestamp, current model, current tool, last activity, top processes. Remote clients show "last seen Xs ago."

### Remote client side

Initial cut: a small static page hosted by Galaxy (or even a Galaxy tool wrapper) that:
- Lists the user's active Orbit sessions (histories tagged `orbit-control`).
- Shows the latest "alive" snapshot.
- Has an input box that creates a new command dataset.
- Polls events outbox for replies.

No new server code on Galaxy — uses the existing API.

## Command vocabulary (v1)

- `status` — return alive snapshot now.
- `tail N` — return last N lines of activity.
- `prompt "..."` — inject a prompt as if the user typed it.
- `stop` — abort current turn.
- `pause` / `resume` — gate further auto-execution.

## Files (sketch)

- `extensions/loom/galaxy/control-channel.ts` — new module: poll commands, dispatch, write events. Reuses the existing Galaxy client.
- `extensions/loom/index.ts` — register the poller alongside the existing Galaxy bootstrap, gated on a setting `enableRemoteControl`.
- `app/src/main/agent.ts` — accept synthetic prompts from the control channel the same way the IPC `prompt` handler does today.
- A tiny static client (Galaxy tool, or a `web/remote-control.html` served by the existing `web/server.ts`).

## Tradeoffs

- **Latency.** Polling at 10–30s means the remote view lags. Acceptable for "is it still working" / "kick off next step" — bad for live streaming. WebSocket relay through Galaxy would be cleaner but needs server-side work that doesn't exist yet. Start with polling; upgrade later if Galaxy grows real-time channels.
- **API quota.** A constant 10s poll is ~8.6k requests/day per session. Fine for one user, watch out if everyone enables it. Mitigate with adaptive backoff: poll fast (5s) right after a command is sent, slow (60s) when idle for N minutes.
- **Security model.** Anyone with the user's Galaxy API key can drive Orbit. That's already the trust boundary for everything else Galaxy-side, but worth being explicit: enabling remote control means "my Galaxy account ≈ root on Orbit's process."
- **Ordering / races.** Two remote clients submitting commands simultaneously: serialize via dataset creation order; reject conflicting verbs (two `stop`s become a no-op).

## Edge cases

- Orbit offline / laptop closed: commands accumulate in the inbox; processed when Orbit reconnects. Heartbeat going stale > N min → remote UI shows "offline."
- Galaxy down: control channel fails closed, Orbit keeps running locally as today.
- Stale commands (queued days ago): include a TTL on each command; skip if older than the threshold.

## Out of scope (for v1)

- Real-time event streaming (covered later, possibly with a server-side relay).
- File transfer between remote client and local Orbit (separate concern; Galaxy datasets already handle this for analysis files).
- Multi-user shared sessions (one Galaxy account = one session for now).

## Related

- #69 — stash project context in Galaxy history (same plumbing, complementary purpose).
- #70 — process monitor for detached PIDs (the heartbeat snapshot would naturally include these).
- #71 — liveness indicator (remote clients have the same "is this thing alive" question).

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.