v0.5.2: shell_bg / remote_shell_bg — background launch tools

server.lua gains a shell_bg tool that launches a detached command via
setsid + nohup + stdio-redirect + &, returns immediately with PID and
log path. Linux-only for MVP (Windows Start-Process equivalent TBD).

hub.lua gains remote_shell_bg, forwarding to backend shell_bg. lmcp-only,
no ssh fallback — fallback for fire-and-forget is semantically murky.

Addresses the 'how do I launch a daemon over lmcp without the sentinel-
file wrapper blocking forever' question. Existing remote_shell keeps
its current synchronous-with-timeout behaviour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-20 09:34:24 +00:00
parent 555beb9fd9
commit b29a2716d1
2 changed files with 55 additions and 1 deletions
+12 -1
View File
@@ -355,7 +355,7 @@ math.randomseed(os.time())
local server = lmcp.new(os.getenv("LMCP_NAME") or "hub-tools", {
port = tonumber(os.getenv("LMCP_PORT") or arg[1]) or 8090,
version = "0.5.0",
version = "0.5.2",
conf = os.getenv("LMCP_HUB_CONF") or "/opt/herding/etc/lmcp-hub.conf",
})
@@ -433,6 +433,17 @@ server:tool("remote_edit_file",
function(a) return call_remote("edit_file", a, false, nil) end
)
server:tool("remote_shell_bg",
"Launch a detached background command on a fleet host (Linux). Returns PID + log path immediately. Requires backend lmcp v0.5.2+.",
{ type = "object", properties = {
host = HOST_ARG,
command = { type = "string", description = "Shell command" },
cwd = { type = "string" },
log = { type = "string", description = "Log file path" },
}, required = { "host", "command" } },
function(a) return call_remote("shell_bg", a, false, nil) end
)
server:tool("remote_list_dir", "List directory entries on a fleet host.",
{ type = "object", properties = {
host = HOST_ARG,