Skip to content

feat(orchestrator): bash port of pa-start / sa-start launchers#3

Open
evannadeau wants to merge 1 commit into
SpawnBox-dev:mainfrom
evannadeau:feat/orchestrator-bash-launchers
Open

feat(orchestrator): bash port of pa-start / sa-start launchers#3
evannadeau wants to merge 1 commit into
SpawnBox-dev:mainfrom
evannadeau:feat/orchestrator-bash-launchers

Conversation

@evannadeau
Copy link
Copy Markdown

@evannadeau evannadeau commented May 12, 2026

Summary

Adds pa-start.sh and sa-start.sh alongside the existing .ps1 / .bat launchers in plugins/orchestrator/skills/install-launchers/scripts/. Users running Claude Code from a POSIX shell (WSL, Linux, macOS) can now spawn PA/SA sessions without PowerShell interop.

Motivation: running pa-start.bat from WSL requires powershell.exe interop, which loses the Linux-native env (PATH, shell aliases, etc.) and adds a Windows-side handoff that's unnecessary when claude itself runs perfectly in WSL bash. This PR closes that gap.

Behavior parity with the .ps1 sources (0.30.28)

  • Resume by display name: greps ~/.claude/projects/<hash>/*.jsonl for Session renamed to: <name> lines, picks newest match, resolves to UUID. Project-hash transform matches CC's own scheme (POSIX paths reduce to s|/|-|g plus leading-dash trim — no \ or : to handle).
  • pa-start.sh singleton check: reads .orchestrator-state/agent-channel/sessions.json via jq, finds role=prime entries with heartbeat <90s, demotes them to subordinate, 2s Ctrl+C grace, then proceeds. jq's fromdateiso8601 rejects fractional seconds, so the heartbeat string is preprocessed with sub("\\.[0-9]+Z$"; "Z") before parsing.
  • Env wiring: MCP_TIMEOUT=30000, ORCHESTRATOR_PROJECT_ROOT, ORCHESTRATOR_AGENT_ROLE (+ SPAWNBOX_ alias), ORCHESTRATOR_PA_PERMISSION_RELAY=1, ORCHESTRATOR_AGENT_NAME (when explicit) — same set as .ps1.
  • PA hardcodes --effort max (per 0.30.28 policy); SA exposes optional --effort with low|medium|high|xhigh|max validation.
  • Marketplace slug uses the same __ORCH_MARKETPLACE__ placeholder the .ps1 sources use; install-launchers SKILL.md sed-substitutes it at copy-into-project time.

Differences from .ps1 (out of scope or N/A for bash)

  • No wt.exe tab spawn / gold-tab color. POSIX shells don't have an equivalent terminal-window manager invocation. exec claude runs in the current shell. Users wanting a separate window run the launcher inside their preferred terminal-emulator tab.
  • No discord-start.sh (yet). The Discord plugin install + the dual --channels / --dangerously-load-development-channels attach is tightly coupled to the Windows-side Discord setup. WSL/Linux users who need Discord-ops can run discord-start.bat via interop or contribute a .sh port in a follow-up.

SKILL.md updates

Install workflow now copies 8 files instead of 6, install -m 0755s the .sh variants, and documents the per-platform variant guide + runtime deps (jq + GNU coreutils for pa-start.sh's singleton check; sa-start.sh has no deps beyond bash 4+). Usage examples block now lists both Windows and POSIX invocations.

Test plan

Tested on Ubuntu-24.04 WSL with bash 5.2.21, jq 1.7.1, GNU coreutils, against a live orchestrator MCP at 0.30.28.

Verified end-to-end./sa-start.sh invoked from a fresh WSL terminal spawned a real claude process which booted the orchestrator MCP and registered in sessions.json:

PID 2023  claude --dangerously-load-development-channels plugin:orchestrator@spawnbox-dev-claude-plugins --name SA-2026-05-11-19-50-34
PID 2172  npm exec bun run plugins/orchestrator/dist/server.js
{
  "session_id": "d3614a60-146d-4e8a-bcd8-535d99e11ea7",
  "id8": "d3614a60",
  "role": "subordinate",
  "name": "SA-2026-05-11-19-50-34",
  "started_at": "2026-05-12T02:50:42.090Z",
  "last_heartbeat_at": "2026-05-12T02:51:12.146Z"
}

Confirms the whole chain: arg passing, env propagation to MCP, role/name registration, agent-channel heartbeat, id8 derivation.

Additional unit-level checks:

  • bash -n syntax check clean on both scripts
  • --help renders header docs
  • sa-start.sh fresh → auto-name SA-YYYY-MM-DD-HH-MM-SS, all 7 env vars set, args in correct order (verified via PATH-shimmed claude that prints what would be exec'd)
  • sa-start.sh --name SA-foo --effort max → name override + --effort max appended after --name
  • sa-start.sh --effort bogus → validation rejects, exit 2
  • pa-start.sh fresh (no prime running) → --effort max hardcoded in args, role=prime env, singleton check correctly no-ops
  • jq singleton-check query dry-run against a live sessions.json correctly returns [] when no prime is active and parses fractional-second ISO-8601 timestamps without error

Not exercised in this PR (low risk, deferred):

  • Singleton-demote path against an actual fresh role=prime heartbeat. The jq query is verified; the mv "$tmp" "$state_file" write path is straightforward. First real PA invocation against a stale-PA state will exercise it.
  • Resume-by-name path against a real Session renamed to: JSONL entry. The grep + ls -t logic is straightforward; first real use will exercise it.

🤖 Generated with Claude Code

Adds pa-start.sh and sa-start.sh alongside the existing .ps1 / .bat
launchers in plugins/orchestrator/skills/install-launchers/scripts/.
Users running Claude Code from a POSIX shell (WSL, Linux, macOS) can
now spawn PA/SA sessions without PowerShell interop.

Behavior parity with the .ps1 sources (current 0.30.28):

- Resume by display name: greps ~/.claude/projects/<hash>/*.jsonl for
  "Session renamed to: <name>" lines, picks newest match, resolves to
  UUID. Project-hash transform matches CC's own scheme (POSIX paths
  reduce to s|/|-|g plus leading-dash trim — no \\ or : to handle).
- pa-start.sh singleton check: reads .orchestrator-state/agent-channel/
  sessions.json via jq, finds role=prime entries with heartbeat <90s,
  demotes them to subordinate, 2s Ctrl+C grace, then proceeds. jq's
  fromdateiso8601 rejects fractional seconds, so the heartbeat string
  is preprocessed with sub("\\.[0-9]+Z$"; "Z") before parsing.
- Env wiring: MCP_TIMEOUT=30000, ORCHESTRATOR_PROJECT_ROOT,
  ORCHESTRATOR_AGENT_ROLE (+ SPAWNBOX_ alias), ORCHESTRATOR_PA_PERMISSION_RELAY=1,
  ORCHESTRATOR_AGENT_NAME (when explicit) — same as .ps1.
- PA hardcodes --effort max (per 0.30.28 policy); SA exposes optional
  --effort with low|medium|high|xhigh|max validation.
- Marketplace slug uses the same __ORCH_MARKETPLACE__ placeholder the
  .ps1 sources use; install-launchers SKILL.md sed-substitutes it at
  copy-into-project time.

Differences from .ps1 (out of scope or not applicable to bash):

- No wt.exe tab spawn / gold-tab color. POSIX shells don't have an
  equivalent terminal-window manager invocation. exec claude runs in
  the current shell. Users wanting a separate window run the launcher
  inside their preferred terminal-emulator tab.
- No discord-start.sh (yet). The Discord plugin install + the dual
  --channels / --dangerously-load-development-channels attach is
  tightly coupled to the Windows-side flow. WSL/Linux users who need
  Discord-ops can run discord-start.bat via interop or contribute a
  .sh port.

SKILL.md updated to copy 8 files instead of 6, install -m 0755 the .sh
variants, and document the new per-platform variant guide + runtime
deps (jq + GNU coreutils for pa-start.sh's singleton check).

Tested on Ubuntu-24.04 WSL with bash 5, jq 1.7, GNU coreutils:
- bash -n syntax check: both scripts clean
- --help renders header docs
- Singleton-check jq query dry-run against a live sessions.json
  correctly returns 0 fresh prime sessions when none are running

Closes the WSL-native gap operators have raised in issue threads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant