You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Windows: tracked skills symlink materialises as a plain file without Developer Mode #554
skills is a tracked symlink in this repo (mode 120000 → .agents/skills). On a Windows checkout with core.symlinks=false (the default for many Git-for-Windows installs, and unavoidable without SeCreateSymbolicLinkPrivilege), Git materialises it as a plain 14-byte text file containing the target path instead of a directory. skills/ therefore does not exist as a directory, and anything that reads through it fails.
Observed during Windows-host validation of #547: the local run reported on the order of 101 failures in the wider suite whose first cause is this materialisation, not the code under test. The same validation also found that the validator's exec-bit check (scripts/validate_provider_input_contract.py:164) fails on Windows on main — that one is fixed by #547.
Why this is an issue and not a patch
There is no test-level fix that makes skills/ a directory while also keeping it a symlink for POSIX consumers. The options all have costs:
Require Developer Mode (or a policy granting SeCreateSymbolicLinkPrivilege) for Windows contributors, and document it as a prerequisite. Cheapest, but makes "clone and run the suite" fail by default on Windows until the developer flips a global OS setting.
Junction instead of symlink — but a junction cannot be committed to Git as a portable, cross-platform artifact; it would still check out as a file.
Stop tracking skills as a symlink and generate it at bootstrap (e.g. a setup step that creates the link/junction, or a real directory populated from .agents/skills). Removes the failure mode for everyone, but changes the kit layout in both this repo and GSA-TTS/agentic-coding-quickstart, and affects any consumer that expects the tracked symlink.
Please decide
Which of the above is acceptable, and for which platforms? Anything that changes the tracked layout needs an ADR, since it is a repository-shape change rather than a code change.
Interim
Until this is resolved, a Windows contributor needs Developer Mode or core.symlinks=false plus awareness that paths under skills/ will not resolve. A short CONTRIBUTING note is being added alongside this issue.
AI-assisted (OpenCode [deepseek-v4.1-flash]); human review required.
That PR is stacked on fix/validator-windows-exec-bit (#547), because the Windows test fixes cannot be demonstrated on main while #547's exec-bit defect is unfixed. Its head ecba5a5 has exactly one check:
Conventional Commit Title = success
No Python Lint & Test, no Pattern Validation, no acq-kits Tests. The change is tests-only, so the risk is modest — but a stacked PR landing without the Python suite having run is a gap, and the PR body has to say "CI is authoritative" while CI is in fact not running.
Why this matters more now
Stacking is the natural way to land a dependent change here, and the Windows epic produces dependent changes by construction (validator fix → harness fix; CRLF fix → guard fix). A filter that silences CI for exactly those PRs makes the stacked pattern unsafe rather than merely awkward.
Options
Drop the branches: [main] filter on pull_request for ci.yml / frontend-skills-qa.yml / zizmor.yml. GitHub already scopes to PRs opened against this repository, so the filter buys little; the cost is CI minutes on PRs targeting a non-main base (few, and short-lived).
Keep the filter and require unstacking before merge — rebase onto main once the base PR merges, then let CI run. Honest, but it means the reviewed diff and the CI-verified diff are different commits.
Leave as-is and document it in CONTRIBUTING, so nobody reads a green PR as "tested".
For contrast, the sibling repo is more permissive: GSA-TTS/agentic-coding-quickstart#667 is stacked on fix/648-msb-ports-crlf and still got 9/9 checks (pre-commit, the bash 3.2 suite, markdown, links, pr-lint). So this is repo-specific configuration, not an inherent property of stacking.
Recommendation: option 1, with option 3 as the interim note.
AI-assisted (OpenCode [deepseek-v4.1-flash]); human review required.
One more data point for the options above: without the privilege, ln -s fails silently
Measured on a default non-elevated Windows host (account in BUILTIN\Administrators, but a filtered Medium-integrity token, so SeCreateSymbolicLinkPrivilege is absent):
$ whoami /priv | grep -i symlink
(no output — privilege not held)
$ ln -s target linkout
ln -s: exit 0
[ -d ] true (fell back to COPY) <- exit code says success, result is a copy
$ MSYS=winsymlinks:nativestrict ln -s target linkout
ln: failed to create symbolic link: Operation not permitted
Two things follow.
1. ln -s success does not mean a link was created. MSYS/Git Bash falls back to copying unless MSYS=winsymlinks:nativestrict is set. Any script that asserts "link created" by exit status is fooled. Worth auditing any host-runnable script that links with ln -s and checks only $?.
2. For reference, the kit path is not affected.integrations/isolation/acq-kits/agentic-coding-playbook/files/home/playbook-clone.sh links $HOME/.config/opencode/AGENTS.md, $HOME/.codex/AGENTS.md, $HOME/.claude/CLAUDE.md, $HOME/.copilot/copilot-instructions.md, and each skill into $HOME/.agents/skills/ — but it runs as a hybrid/v1 kit startup command inside the sandbox, so those ln -sfn calls execute against the guest's Linux filesystem. No Windows privilege is involved and no host mounts are used (checked: the only host-side reference to these paths in the quickstart backends is acq.backends/sbx.sh:1389, which runs sh -c via sbx execin the guest to clear a dangling opencode.jsonc symlink).
The host-side symlink exposure is therefore limited to the two cases in this issue: git materialising the tracked skills entry, and test fixtures calling os.symlink.
Consequence for option 1 (require Developer Mode): if that is the chosen direction, the guidance should specify MSYS=winsymlinks:nativestrict for any host-run MSYS shell, so a missing privilege fails loudly instead of degrading into copies that look correct.
AI-assisted (OpenCode [deepseek-v4.1-flash]); human review required.
Activity
mogul commentedon Oct 29, 2026
Related finding: PR CI only runs for PRs whose base is
mainConnecting this to the same Windows/CI-coverage theme, since it came out of the Windows validation work.
Three workflows in
.github/workflows/gate theirpull_requesttrigger onbranches: [main]:ci.ymlpull_request: branches: [main]— alsopushandmerge_groupfrontend-skills-qa.ymlpull_request: branches: [main]zizmor.ymlpull_request: branches: [main]pr-lint.ymlpull_request:(unfiltered) — runs for any baseSo a PR based on anything other than
maingets onlypr-lint.Observed on #555
That PR is stacked on
fix/validator-windows-exec-bit(#547), because the Windows test fixes cannot be demonstrated onmainwhile #547's exec-bit defect is unfixed. Its headecba5a5has exactly one check:No
Python Lint & Test, noPattern Validation, noacq-kits Tests. The change is tests-only, so the risk is modest — but a stacked PR landing without the Python suite having run is a gap, and the PR body has to say "CI is authoritative" while CI is in fact not running.Why this matters more now
Stacking is the natural way to land a dependent change here, and the Windows epic produces dependent changes by construction (validator fix → harness fix; CRLF fix → guard fix). A filter that silences CI for exactly those PRs makes the stacked pattern unsafe rather than merely awkward.
Options
branches: [main]filter onpull_requestforci.yml/frontend-skills-qa.yml/zizmor.yml. GitHub already scopes to PRs opened against this repository, so the filter buys little; the cost is CI minutes on PRs targeting a non-main base (few, and short-lived).mainonce the base PR merges, then let CI run. Honest, but it means the reviewed diff and the CI-verified diff are different commits.For contrast, the sibling repo is more permissive: GSA-TTS/agentic-coding-quickstart#667 is stacked on
fix/648-msb-ports-crlfand still got 9/9 checks (pre-commit, the bash 3.2 suite, markdown, links, pr-lint). So this is repo-specific configuration, not an inherent property of stacking.Recommendation: option 1, with option 3 as the interim note.
AI-assisted (OpenCode [deepseek-v4.1-flash]); human review required.
mogul commentedon Oct 29, 2026
One more data point for the options above: without the privilege,
ln -sfails silentlyMeasured on a default non-elevated Windows host (account in
BUILTIN\Administrators, but a filtered Medium-integrity token, soSeCreateSymbolicLinkPrivilegeis absent):Two things follow.
1.
ln -ssuccess does not mean a link was created. MSYS/Git Bash falls back to copying unlessMSYS=winsymlinks:nativestrictis set. Any script that asserts "link created" by exit status is fooled. Worth auditing any host-runnable script that links withln -sand checks only$?.2. For reference, the kit path is not affected.
integrations/isolation/acq-kits/agentic-coding-playbook/files/home/playbook-clone.shlinks$HOME/.config/opencode/AGENTS.md,$HOME/.codex/AGENTS.md,$HOME/.claude/CLAUDE.md,$HOME/.copilot/copilot-instructions.md, and each skill into$HOME/.agents/skills/— but it runs as ahybrid/v1kit startup command inside the sandbox, so thoseln -sfncalls execute against the guest's Linux filesystem. No Windows privilege is involved and no host mounts are used (checked: the only host-side reference to these paths in the quickstart backends isacq.backends/sbx.sh:1389, which runssh -cviasbx execin the guest to clear a danglingopencode.jsoncsymlink).The host-side symlink exposure is therefore limited to the two cases in this issue: git materialising the tracked
skillsentry, and test fixtures callingos.symlink.Consequence for option 1 (require Developer Mode): if that is the chosen direction, the guidance should specify
MSYS=winsymlinks:nativestrictfor any host-run MSYS shell, so a missing privilege fails loudly instead of degrading into copies that look correct.AI-assisted (OpenCode [deepseek-v4.1-flash]); human review required.