diff --git a/skills/in-progress/spawn/SKILL.md b/skills/in-progress/spawn/SKILL.md index 7e97adc..ac3bfb1 100644 --- a/skills/in-progress/spawn/SKILL.md +++ b/skills/in-progress/spawn/SKILL.md @@ -1,19 +1,19 @@ --- name: spawn -description: Hand the current conversation off to a fresh background agent — claude or codex — that picks up the work immediately. -argument-hint: "[claude|codex] What will the next session be used for?" +description: Hand the current conversation off to a fresh background agent that picks up the work immediately. +argument-hint: "[agent] What will the next session be used for?" disable-model-invocation: true --- Write a handoff summary of the current conversation so a fresh agent can continue the work, then spawn the agent with it via the bundled [spawn.sh](spawn.sh) — run it, never read it: ```bash -bash /spawn.sh "" - <<'PROMPT' +bash /spawn.sh "" - <<'PROMPT' PROMPT ``` -Spawn `claude` unless the user named `codex`. The agent starts in the current working directory; the script prints how the user monitors the session — relay that. +`` is one of `claude | codex | pi | cursor | opencode | copilot`. Spawn the agent you are running as, unless the user named another. The agent starts in the current working directory; the script prints how the user monitors and manages the session — relay that. The handoff summary: diff --git a/skills/in-progress/spawn/spawn.sh b/skills/in-progress/spawn/spawn.sh index 93aad32..e191863 100755 --- a/skills/in-progress/spawn/spawn.sh +++ b/skills/in-progress/spawn/spawn.sh @@ -1,11 +1,17 @@ #!/usr/bin/env bash -# spawn.sh [prompt|-] +# spawn.sh [prompt|-] # Launches a background agent session seeded with the prompt. # Prompt is read from stdin when the third argument is omitted or '-'. +# +# claude has native managed background jobs (claude --bg / claude agents). +# Every other agent is spawned interactively inside herdr when its server is +# running (list/read/send/attach management); otherwise as a supervised +# one-shot under the user's systemd session (status/logs/stop management). set -euo pipefail usage() { - echo "usage: spawn.sh [prompt|-] (prompt read from stdin when omitted or '-')" >&2 + echo "usage: spawn.sh [prompt|-]" >&2 + echo " prompt is read from stdin when omitted or '-'" >&2 exit 2 } @@ -19,24 +25,67 @@ if [ "$prompt" = "-" ]; then fi [ -n "$prompt" ] || { echo "spawn.sh: empty prompt" >&2; exit 2; } -case "$agent" in -claude) +if [ "$agent" = "claude" ]; then claude --bg --name "$name" "$prompt" echo "Spawned claude session '$name'. Manage it with: claude agents" - ;; -codex) - slug="$(printf '%s' "$name" | tr '[:upper:] ' '[:lower:]-' | tr -cd 'a-z0-9-')" - dir="${TMPDIR:-/tmp}/codex-spawns" - mkdir -p "$dir" - base="$dir/${slug:-session}-$(date +%Y%m%d-%H%M%S)" - nohup codex exec --sandbox workspace-write --cd "$PWD" \ - -o "$base.last.md" - <<<"$prompt" >"$base.log" 2>&1 & - echo "Spawned codex session '$name' (pid $!)." - echo " log: $base.log" - echo " final answer: $base.last.md" - echo " follow with: tail -f $base.log" - ;; -*) - usage - ;; + exit 0 +fi + +# Interactive invocation, seeded with the prompt — used inside herdr panes. +case "$agent" in +codex) interactive=(codex "$prompt") ;; +pi) interactive=(pi "$prompt") ;; +cursor) interactive=(cursor-agent "$prompt") ;; +opencode) interactive=(opencode --prompt "$prompt") ;; +copilot) interactive=(copilot -i "$prompt") ;; +*) usage ;; +esac + +if herdr agent list >/dev/null 2>&1; then + herdr agent start "$name" --cwd "$PWD" --no-focus -- "${interactive[@]}" + echo "Spawned $agent session '$name' in herdr." + echo " list: herdr agent list" + echo " read: herdr agent read '$name'" + echo " steer: herdr agent send '$name' ''" + echo " attach: herdr agent attach '$name'" + exit 0 +fi + +command -v systemd-run >/dev/null 2>&1 || { + echo "spawn.sh: no herdr server running and systemd-run unavailable — launch herdr and retry" >&2 + exit 1 +} + +# Non-interactive one-shot — flags keep the run from blocking on approvals. +case "$agent" in +codex) oneshot=(codex exec --sandbox workspace-write --skip-git-repo-check "$prompt") ;; +pi) oneshot=(pi -p "$prompt") ;; +cursor) oneshot=(cursor-agent -p --force --output-format text "$prompt") ;; +opencode) oneshot=(opencode run --title "$name" "$prompt") ;; +copilot) oneshot=(copilot -p "$prompt" --allow-all-tools) ;; +esac + +# The systemd user manager doesn't inherit this shell's PATH; resolve the +# binary now and pass PATH through for any children it spawns. +bin="$(command -v "${oneshot[0]}")" || { + echo "spawn.sh: ${oneshot[0]} is not installed" >&2 + exit 1 +} +oneshot[0]="$bin" + +slug="$(printf '%s' "$name" | tr '[:upper:] ' '[:lower:]-' | tr -cd 'a-z0-9-')" +unit="spawn-${slug:-session}-$(date +%H%M%S)" +systemd-run --user --unit "$unit" --working-directory="$PWD" \ + --setenv=PATH="$PATH" --setenv=HOME="$HOME" "${oneshot[@]}" >/dev/null 2>&1 + +echo "Spawned $agent session '$name' as user unit $unit (no herdr server running)." +echo " status: systemctl --user status $unit" +echo " logs: journalctl --user -u $unit -f" +echo " stop: systemctl --user stop $unit" +case "$agent" in +codex) echo " resume: codex exec resume " ;; +pi) echo " resume: pi -c (from this directory)" ;; +cursor) echo " resume: cursor-agent resume" ;; +opencode) echo " resume: opencode run -c (or: opencode session list)" ;; +copilot) echo " resume: copilot --resume" ;; esac