Skip to content

fix: name the Windows command interpreter in the Runtime prompt section - #1573

Open
Ramnath0521 wants to merge 2 commits into
TokenRhythm:mainfrom
Ramnath0521:fix/issue-941
Open

fix: name the Windows command interpreter in the Runtime prompt section#1573
Ramnath0521 wants to merge 2 commits into
TokenRhythm:mainfrom
Ramnath0521:fix/issue-941

Conversation

@Ramnath0521

Copy link
Copy Markdown

Refs #941.

What is actually wrong

The issue attributes the Unix-only command to the bundled PPTX skill's Bash-oriented examples. That is not where it comes from — tail appears nowhere in src/opensquilla/skills/bundled/pptx/, so editing SKILL.md would not change this behaviour. The | tail -3 was produced by the model, and the reason it reaches for Bash idioms is upstream of the skill.

TurnRunner builds the Runtime prompt block in engine/runtime.py:

runtime_info = {
    "os": os_name,
    "shell": os.environ.get("SHELL", ""),
    "workspace_dir": ...,
}

SHELL is a POSIX variable; Windows does not set it. identity/templates/system_prompt.j2 renders the field unconditionally, so every Windows turn ships this:

## Runtime

- OS: Windows
- Shell:

An empty declared field is worse than an absent one: the model is told a shell exists, given nothing to identify it, and falls back to the POSIX idioms that dominate its priors — | tail -3, 2>&1, where soffice || echo. Meanwhile COMSPEC is populated and unused.

Reproduction

Windows 11, Python 3.12, run from PowerShell (not Git Bash — Git Bash sets SHELL and masks this):

import os, platform
print(platform.system())              # Windows
print(repr(os.environ.get("SHELL", "")))   # ''
print(repr(os.environ.get("COMSPEC", ""))) # 'C:\WINDOWS\system32\cmd.exe'

Rendering the real prompt through assemble_system_prompt with runtime_info built as runtime.py builds it yields the blank - Shell: line above. After the change the same render yields:

## Runtime

- OS: Windows
- Shell: C:\WINDOWS\system32\cmd.exe

The change

process_tree.default_command_shell() names the interpreter that actually runs agent commands, and create_owned_subprocess_shell now calls it for its Windows branch instead of reading COMSPEC separately. The value reported to the model and the value handed to CreateProcess are therefore the same expression and cannot drift.

POSIX behaviour is deliberately unchanged — still $SHELL. Worth noting for a maintainer: on POSIX create_owned_subprocess_shell execs /bin/sh rather than $SHELL, so that field is arguably imprecise there too. That is pre-existing, orthogonal to a Windows report, and left alone.

Refs rather than Fixes: naming the interpreter removes the cause of the guessing, but it makes correct commands likely, not guaranteed. The issue's other asks — not fail-chaining install/verify/discovery into one command, and treating a missing LibreOffice as loss of visual QA only — are separate behavioural changes and are not in this PR.

Scope

Scope boundary: process_tree.default_command_shell() plus its two call sites — the Windows branch of create_owned_subprocess_shell and the runtime_info["shell"] value in engine/runtime.py.

Non-goals: the PPTX skill text, the shape of generated dependency probes, LibreOffice/visual-QA fallback behaviour, and POSIX shell reporting.

Branch

Base branch: main

Target exception: N/A

Issue

Linked issue: Refs #941

Release Note

Release note: The agent's Runtime prompt section now names the Windows command interpreter (COMSPEC) instead of leaving the shell field blank.

Tests

Ruff: ruff check src tests — All checks passed. (ruff format --check reports these files as unformatted, but reports them identically on unmodified main; I confirmed that against a pristine checkout and left it alone. CI does not run ruff format.)

Pytest, on Windows 11 / Python 3.12, in three passes:

  • Targeted — pytest tests/test_process_tree.py tests/test_identity -q: 117 passed, 14 skipped.
  • E2E — pytest tests/functional -v: 20 passed, 15 skipped in 80s (skips are credential-gated live provider/Telegram/browser tests). This includes test_gateway_stop_process_tree_e2e.py, the closest e2e coverage of the modified module, which passes. These must be run serially: under pytest -n auto the socket-binding gateway tests deadlock, which is presumably why CI gives them a dedicated job.
  • Full — pytest -q -n auto --ignore=tests/functional --ignore=tests/live: 25,100 passed, 207 failed, 718 skipped.

On those 207: they are pre-existing on this platform, not introduced here. Re-running that exact set of ids against unmodified main gives 186 failures, versus 187 with the patch applied — and the two sets differ in both directions (8 fail only with the patch, 7 only without), which is the signature of parallel-execution flakiness rather than a regression. All 7 that failed only on the patched side pass when run serially. The bulk are Windows-environment failures concentrated in test_opensquilla_home_migration.py (61) and test_turn_ingress_rpc.py (25), neither of which this change can reach.

I have not tried to fix any of them; flagging the number so it is not mistaken for something this PR caused.

Build: mypy src/opensquilla --show-error-codes — Success: no issues found in 1547 source files.

Regression tests: added

Notes: Four cases in tests/test_process_tree.py. Two cover the bug and two are controls, so the suite cannot pass by breaking the other platform:

Test Purpose
test_default_command_shell_reports_comspec_on_windows the bug — fails on main
test_default_command_shell_falls_back_when_comspec_missing the field must never be empty on Windows
test_default_command_shell_keeps_posix_shell control — POSIX still reports the login shell
test_default_command_shell_is_empty_when_posix_shell_unset control — pins the POSIX empty case as pre-existing, not something this change claims to fix

All four were written first and confirmed failing with AttributeError: module 'opensquilla.process_tree' has no attribute 'default_command_shell' before the implementation existed. The existing POSIX assertion in tests/test_identity/test_user_profile_prompt.py (- Shell: /bin/bash) still passes unchanged.

Environment note: checks were run against uv sync --extra dev --extra recommended --extra mcp --frozen, matching CI, after an earlier run on a stale environment produced misleading tool-version results.

Maintainer Live Check

Maintainer live check: no

Surface: N/A

Third-Party Origin

Third-party origin: none


Authored by Claude (an AI coding agent) on the account owner's machine and with their authorization. The reproduction, the failing-test-first sequence and every check above were genuinely executed here rather than asserted; the account owner reviewed the diff before this was opened. Flagging the AI authorship plainly rather than leaving it to be inferred — happy to take any correction in review.

🤖 Generated with Claude Code

Ramnath0521 and others added 2 commits September 6, 2026 02:06
TurnRunner built the Runtime prompt block with
os.environ.get("SHELL", ""). SHELL is a POSIX variable that Windows
never sets, and system_prompt.j2 renders the field unconditionally, so
every Windows turn told the model:

    ## Runtime

    - OS: Windows
    - Shell:

An empty declared field is worse than an absent one: the model is told a
shell exists, given nothing to identify it, and falls back to POSIX
idioms that then fail on the Windows command runner.

process_tree.default_command_shell() names the interpreter that actually
runs agent commands, and create_owned_subprocess_shell now calls it for
its Windows branch instead of reading COMSPEC separately, so the value
reported to the model and the value handed to CreateProcess cannot
drift. POSIX behaviour is unchanged.

Refs TokenRhythm#941

Co-Authored-By: Claude Opus 5 <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