Skip to content

fix(automation): launch scheduled workers under PowerShell - #5

Draft
paulork wants to merge 2 commits into
mainfrom
fix/automation-pwsh-launch
Draft

paulork wants to merge 2 commits into
mainfrom
fix/automation-pwsh-launch

Conversation

@paulork

@paulork paulork commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Summary

Scheduled automation workers now start when the pane shell is PowerShell (pwsh or Windows powershell). Before this change the worker pane printed a ParserError, the run stayed running forever, and with the default overlap: skip every later occurrence was skipped. cmd and POSIX shells behave as before.

Closes RizRiyz#507

What

  • src/app/board.rs:
    • New WorkerShell (Posix, PowerShell, Cmd). It classifies the pane's shell by executable name, case-insensitively, with or without .exe and a path. Unix panes always use Posix; an unrecognised Windows shell keeps the POSIX form, as manual_agent_runner_line already did.
    • automation_agent_launch_line now validates and returns an AutomationWorkerLaunch (executable, task, automation and run ids). The line is rendered in task_start once the worker pane exists, because its syntax depends on that pane's shell:
      • PowerShell: & 'C:\…\luvus.exe' __automation-worker t1 a1 r1. The call operator is required; the path is a literal single-quoted string, so $ and backticks don't expand, and every quote character PowerShell recognises (including typographic ones) is doubled.
      • cmd: "C:\…\luvus.exe" __automation-worker t1 a1 r1, unchanged.
      • POSIX: LUVUS_TASK_ID=t1 '/…/luvus' __automation-worker t1 a1 r1 on Unix, unchanged. Git Bash on Windows keeps the form without the prefix, as before.
      • Ids made only of [A-Za-z0-9_.-] stay bare; anything else is quoted for the shell.
    • manual_agent_runner_line uses the same classification. Its output is unchanged.
    • shell_quote is removed. Its only remaining caller, a Unix-only test, uses WorkerShell::Posix.quote.
  • The worker still invokes the owning server binary (current_exe) directly, as before.

Why

automation_agent_launch_line always sent "<exe>" __automation-worker … on Windows. PowerShell parses a leading quoted string as an expression, so the next token fails:

ParserError: Unexpected token '__automation-worker' in expression or statement.

It fails before any agent starts, so it affects every agent, and nothing reports the failure. The run and its ORCH task stay running, and overlap: skip turns every later occurrence into skipped ("previous run is still active"). Manual tasks already used & for PowerShell in manual_agent_runner_line; scheduled workers didn't.

Screenshots

The same scheduled Claude automation in both cases: {"shell": "pwsh"}, --every 60, workspace mode, read-only, isolated LUVUS_HOME, PowerShell 7.6.6.

Before, on main (0062178): the worker pane rejects the launch line with a ParserError.

before-worker-pane

Before: the run history shows the later occurrences skipped because the first run is still "active".

before-automation-history

With this PR: the worker pane runs & '…luvus.exe' __automation-worker t3 a1 r3 and Claude answers OK.

after-worker-pane

With this PR: three consecutive occurrences finished.

after-automation-history
CLI output, before and after
# BEFORE: main 0062178 (unfixed), Windows 11, PowerShell 7.6.6, isolated LUVUS_HOME
config.json: {"shell": "pwsh"}  |  automation a1: --agent claude --every 60 --mode workspace --access read-only (overlap: skip)

$ luvus automation history a1   (oldest first)
  r1  running    task=t1  error=None
  r2  skipped    task=-   error=previous run is still active
  r3  skipped    task=-   error=previous run is still active

$ luvus task list
  t1  running  pane=2

$ luvus pane read 2
  PowerShell 7.6.6
  PS C:\luvus-wt507-repo> "C:\luvus-wt507-home\luvus-main.exe" __automation-worker
   t1 a1 r1
  ParserError:
  Line |
     1 |  "C:\luvus-wt507-home\luvus-main.exe" __automation-worker t1 a1 r1
       |                                       ~~~~~~~~~~~~~~~~~~~
       | Unexpected token '__automation-worker' in expression or statement.
  PS C:\luvus-wt507-repo>


# AFTER: fix branch claude/fix-automation-pwsh-launch-45fdbd (base 52def96), Windows 11, PowerShell 7.6.6, isolated LUVUS_HOME
config.json: {"shell": "pwsh"}  |  automation a1: --agent claude --every 60 --mode workspace --access read-only (overlap: skip)

$ luvus automation history a1   (oldest first)
  r1  succeeded  task=t1  error=None
  r2  succeeded  task=t2  error=None
  r3  succeeded  task=t3  error=None

$ luvus task list
  t1  done     pane=2
  t2  done     pane=3
  t3  done     pane=4

$ luvus pane read 2
  PowerShell 7.6.6
  PS C:\luvus-wt507-repo> & 'C:\luvus-wt507-bin\after\luvus.exe' __automation-work
  er t1 a1 r1
  OK
  PS C:\luvus-wt507-repo>

$ luvus pane read 3
  PowerShell 7.6.6
  PS C:\luvus-wt507-repo> & 'C:\luvus-wt507-bin\after\luvus.exe' __automation-work
  er t2 a1 r2
  OK
  PS C:\luvus-wt507-repo>

$ luvus pane read 4
  PowerShell 7.6.6
  PS C:\luvus-wt507-repo> & 'C:\luvus-wt507-bin\after\luvus.exe' __automation-work
  er t3 a1 r3
  OK
  PS C:\luvus-wt507-repo>

Verification

Windows 11, rebased on 0062178.

  • cargo fmt --all --check (Rust 1.99.0, the current stable used by CI)
  • cargo clippy --all-targets -- -D warnings (Rust 1.99.0, Windows)
  • New tests in app::board:
    • worker_shell_classifies_configured_windows_shells
    • automation_worker_line_uses_the_powershell_call_operator (paths with spaces, ', $, backticks, typographic quotes, ids that need quoting)
    • automation_worker_line_for_cmd_quotes_without_call_operator
    • automation_worker_line_for_posix_shells_single_quotes (with and without the LUVUS_TASK_ID prefix)
    • manual_runner_line_matches_the_shell_family
  • automation_commands_use_reviewed_headless_access_profiles updated for the new return type; all 79 app::board::tests pass after the rebase.
  • End to end with the debug binary, in an isolated LUVUS_HOME and named sessions. The production server was not touched.
    • {"shell": "pwsh"}, Claude, --every 60: r1, r2 and r3 succeeded, tasks done, nothing skipped.
    • {"shell": "cmd"}, Claude, automation run: r1 succeeded, launch line unchanged.
    • The same pwsh scenario on unmodified main reproduced the bug (r1 stuck running, r2 and r3 skipped).
  • cargo test --locked: not run in full on this Windows checkout, which has about 25 pre-existing failures on unmodified main. CI covers the full suite on Ubuntu and macOS.

Notes

Render the automation worker launch line for the pane's shell once the
pane exists. PowerShell gets the call operator and a literal
single-quoted path, cmd keeps double quotes, and POSIX shells keep
single quotes and the LUVUS_TASK_ID prefix. Share shell classification
with the manual task runner.

Closes RizRiyz#507
@github-actions github-actions Bot added area: orchestration bug Something isn't working labels Oct 16, 2026
Split the configured shell on both path separators instead of using
Path::file_name, which ignores backslashes on Unix. Panes still use
POSIX syntax on Unix; this only lets the classification test cover
Windows shell paths on Unix CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: orchestration bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scheduled automation workers never start when the pane shell is PowerShell

1 participant