portal_job
Run commands in the background and manage them with job IDs. Poll for incremental output, cancel, or list jobs. Designed for long-running tasks on remote hosts.
Instructions
Run a command in the background and get a job_id back immediately, so you can keep thinking while it runs, poll for incremental output, and cancel it. Use this for long tasks; for a command that finishes quickly just use portal_exec (it waits and returns the result).
Actions
action="submit": start
commandonhostin the background (nohup + remote tmp files), returning {job_id, host, remote_pid, started_at, status} right away. The job keeps running even if the SSH connection drops. NOTE: sudo / secret injection are NOT supported in the background and passing use_sudo=True or secrets=[...] here is rejected with guidance (sudo -S needs a stdin the nohup process detaches; secrets would land on argv /psfor the whole job) — run those with portal_exec (one-shot) or portal_shell instead.action="poll": fetch this job's status + new output on demand, not all at once. Required: job_id. Pass since= to get only the bytes produced since then; each poll returns at most
max_bytes(default 64 KiB) so a big backlog doesn't dump in one shot. Keep polling with since=new_offset while the returnedmoreis true to drain the rest. Or pass tail=N to just peek the last N lines. Returns {status: running|done|failed|cancelled| unknown, exit_code?, output_chunk, new_offset, more, finished_at?}.action="cancel": signal the job. Required: job_id. signal=TERM (default) or KILL. Best-effort —
killdoesn't guarantee instant death; poll to confirm. Returns {job_id, signal_sent, status_after}.action="list": list all known jobs {job_id, host, status, started_at, age_s, exit_code?}.
Limits (L1): job_ids are best-effort persisted across a server restart
(the table reloads from /jobs.json and a poll re-probes the remote
PID); set PORTAL_JOB_PERSIST=0 to disable. It's not a durable queue — a
crash mid-write loses the view, but the remote process keeps running and is
recoverable via ps. Finished jobs are swept after a TTL (default 1h) and
their tmp files removed. There is a cap on concurrent live jobs (default 50).
Manual fallback (no portal_job): you can always background a command yourself with portal_exec(command="nohup mycmd >/tmp/x.log 2>&1 & echo $!") and poll the log with portal_exec(command="tail /tmp/x.log").
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| host | No | ||
| tail | No | ||
| since | No | ||
| action | Yes | ||
| job_id | No | ||
| signal | No | TERM | |
| command | No | ||
| secrets | No | ||
| use_sudo | No | ||
| max_bytes | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |