From 76fe691f0b03e454df70d16fbbf919bc97ee3dc2 Mon Sep 17 00:00:00 2001 From: Valentin Haudiquet Date: Wed, 20 May 2026 09:44:33 +0200 Subject: [PATCH] spec: update spec - new "p worker" command wrapping register/workers/default - tmux session updates --- SPEC.md | 143 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 49 deletions(-) diff --git a/SPEC.md b/SPEC.md index 23430d9..9171141 100644 --- a/SPEC.md +++ b/SPEC.md @@ -41,7 +41,14 @@ Communication happens over SSH port forwarding — no extra open ports needed. p -- ``` Sync the current directory to the default worker and run `` on it. -Attaches to the job's output by default. `Ctrl+C` detaches without killing the job. +Attaches to the job's tmux session immediately. `Ctrl+B D` detaches without +killing the job. `Ctrl+C` sends SIGINT to the running process (standard behavior). + +When the job finishes, the session stays open and displays: +``` +--- Job done [exit 0]. Press any key to detach. --- +``` +This lets the user read final output before returning to their shell. ``` p -- @@ -65,7 +72,10 @@ command, status, duration. Style inspired by `docker ps` / `lxc list`. ``` p attach ``` -Re-attach to the console of a running job (via tmux). Supports partial IDs. +Re-attach to the tmux session of a running job. Supports partial IDs. +Behaves identically to the initial attach: `Ctrl+B D` detaches, and if the job +has already finished the "press any key" screen is shown. +Only works on **running** jobs. For finished jobs, use `p logs`. ``` p logs @@ -90,26 +100,33 @@ p rm Remove a job record and its remote work directory. Refuses to remove a running job without `--force`. -### Workers +### Worker management ``` -p register [] +p worker register [-n ] ``` Register a worker. The connection string is an SSH target (`user@host`, -`user@host:port`, or an SSH config alias). If `` is omitted, the -hostname is used. The first registered worker becomes the default. +`user@host:port`, or an SSH config alias). If `-n` is omitted, the hostname +is used as the name. The first registered worker becomes the default. ``` -p workers +p worker ls ``` -List registered workers with their name, connection string, and reachability -status. +List registered workers with their name and connection string. +Pass `--check` / `-c` to also probe reachability over SSH (slow). ``` -p default +p worker rm +``` +Unregister a worker. Refuses if the worker has running jobs. + +``` +p worker default ``` Set the default worker. +--- + ## Directory Sync - Uses `rsync` over SSH. @@ -121,6 +138,63 @@ Set the default worker. - No automatic sync-back after job completion. Use `p pull` to retrieve specific artifacts. +## Attach / Detach Mechanics + +Jobs run inside a `tmux` session on the worker. `p` attaches to the session +immediately after starting the job. + +### Status bar +The tmux session has a custom status bar showing: +``` + p- beefy make [running] 0:02:14 +``` +Fields: job short-ID, worker name, command (truncated), status, elapsed time. + +### Key bindings while attached +| Key | Effect | +|---|---| +| `Ctrl+B D` | Detach from session. Job keeps running. | +| `Ctrl+C` | Sends SIGINT to the foreground process (standard terminal behavior). | + +### On job completion +When the job's process exits, `run.sh` writes the exit code and then displays: +``` +--- Job done [exit 0]. Press any key to detach. --- +``` +The tmux session stays open (`remain-on-exit on` for the window) so the user +can scroll through final output. Pressing any key detaches the client and +returns to the local shell. `p` then reads the exit code and prints a summary. + +### `p attach` on a finished job +If the job has already finished and the tmux session is still open (user has +not yet pressed a key), `p attach` reconnects to the "press any key" screen. +Once the key is pressed, the session closes. For a fully-closed session, use +`p logs` instead. + +> **Worker requirements:** `tmux` and `rsync` must be available on the worker +> (standard on most Linux systems). The `p-agent` binary is auto-uploaded by `p`. + +--- + +## Job Status & Notification + +The **p-agent** runs as a lightweight background process on the worker +(started automatically, not a system service). It: + +- Manages job launch and tmux session creation +- Tees output to `output.log` +- Writes `exitcode` on completion +- Notifies the client over the SSH reverse tunnel when a job finishes + +The client maintains a local job database (`~/.local/share/p/jobs/.json`) +mirroring job state. `p ls` reads from this local store (fast, no SSH), +updated in real time while attached, and via agent notifications otherwise. + +### Degraded mode (agent unreachable / client was offline) +If the client missed a completion notification, `p ls` marks affected jobs as +`unknown`. The next `p ls` SSH-polls all workers with known-running jobs to +reconcile state. + ## Worker-side Layout All data lives under `~/.p/` on the worker (no root access required). @@ -142,47 +216,13 @@ All data lives under `~/.p/` on the worker (no root access required). / # rsync'd copy of client CWD for this job ``` -## Attach / Detach Mechanics - -Jobs run inside a `tmux` session on the worker (requirement: `tmux` must be -installed on the worker). Output is simultaneously captured to `output.log` -via `tmux pipe-pane` or a `tee` wrapper. - -- `p attach ` → `ssh -t worker "tmux attach -t p-"` -- `Ctrl+C` while attached → sends detach signal to tmux, **not** SIGINT to - the job. The job keeps running. -- `p attach` only works on **running** jobs. For finished jobs, use `p logs`. - -> **Note:** `tmux` is the only required dependency on the worker beyond a -> standard POSIX environment. The `p-agent` binary and `rsync` are also -> required; `p` ensures the agent is present automatically. `rsync` must be -> available on the worker (standard on most Linux systems). - -## Job Status & Notification - -The **p-agent** runs as a lightweight background process on the worker -(started automatically, not a system service). It: - -- Manages job launch and tmux session creation -- Tees output to `output.log` -- Writes `exitcode` on completion -- Notifies the client over the SSH reverse tunnel when a job finishes - -The client maintains a local job database (`~/.local/share/p/jobs.db`, -SQLite) mirroring job state. `p ls` reads from this local DB (fast, no SSH), -updated in real time while attached, and via agent notifications otherwise. - -### Degraded mode (agent unreachable / client was offline) -If the client missed a completion notification, `p ls` marks affected jobs as -`unknown`. Running the next `p ls` SSH-polls all -workers with known-running jobs to reconcile state. ## Configuration File: `~/.config/p/config.yaml` ```yaml -default_worker = "beefy" +default_worker: beefy workers: - name: beefy connection: user@192.168.1.50 @@ -194,9 +234,10 @@ workers: ``` ID WORKER CWD COMMAND STATUS DURATION -a3f2 beefy ~/projects/foo make running 0:02:14 -7c91 beefy ~/projects/bar cargo test done [0] 0:01:03 -b004 cloud ~/scripts ./bench.sh done [1] 0:00:47 +-------- ------ --------------- --------------- --------- -------- +a3f2b091 beefy ~/projects/foo make running 0:02:14 +7c91d302 beefy ~/projects/bar cargo test done [0] 0:01:03 +b004f123 cloud ~/scripts ./bench.sh done [1] 0:00:47 ``` ## Open Questions @@ -216,4 +257,8 @@ b004 cloud ~/scripts ./bench.sh done [1] 0:00:47 should prompt to clean up. - **Non-Linux workers**: tmux availability and path conventions may differ on - macOS workers. Out of scope for Phase 1. + macOS workers. Out of scope for now. + +- **Ctrl+C → detach** (future): it would be nicer if Ctrl+C detached the + session instead of sending SIGINT to the job, matching the spirit of the + tool. This requires per-session tmux key table configuration and is deferred.