Skip to content

ci: add Windows runner to CI matrix #634

@memtomem

Description

@memtomem

Background

Windows isn't currently CI-tested or formally documented as supported.
This issue proposes promoting Windows from implicitly unsupported to
CI-tested, motivated by PR #633 — which fixed 5 tests (one of which
propagates to a 14-test class via its fixture) that hit
OSError: [WinError 1314] (client does not hold the required privilege)
because they call os.symlink / Path.symlink_to. CI never noticed
because every job in .github/workflows/ci.yml runs on ubuntu-latest.

There's no broken cross-platform promise to fix here — README.md,
packages/memtomem/README.md, and CONTRIBUTING.md don't claim Windows
support today. The relevant prior art is the implicit POSIX-only stance
of the mm: command not found README tip (which mentions ~/.local/bin
on macOS/Linux only). What this issue proposes is a deliberate step
toward supporting Windows by adding the CI signal first.

There are likely other latent Windows-specific issues hiding behind the
ubuntu-only blind spot — see "Likely first-run failures" below.

Proposal

Add windows-latest (and probably macos-latest while we're at it) to
selected jobs in .github/workflows/ci.yml. The repo currently has 6
jobs; per-job recommendations:

Job OS matrix recommendation Why
lint ubuntu only Ruff output is identical across OSes; matrix would just slow PRs
typecheck ubuntu only mypy is platform-agnostic (advisory anyway per CLAUDE.md)
test [ubuntu-latest, windows-latest, macos-latest] The actual surface this issue is about
golden-path (ONNX bge-m3) matrix Cache key already uses ${{ runner.os }} — prepared for it; ONNX/fastembed has known cross-platform behavior worth pinning
llm-nightly (optional) ubuntu only Opt-in nightly, not on PR fast path
notebooks matrix (low priority) Jupyter on Windows has its own quirks; defer until base test job is green

Concretely:

test:
  strategy:
    fail-fast: false
    matrix:
      os: [ubuntu-latest, windows-latest, macos-latest]
  runs-on: ${{ matrix.os }}

Notes on cost / latency

Actions minutes are free and unlimited for public repos (this repo
is public), so the 2x/10x billing multipliers for Windows/macOS don't
apply here
. The real concern is PR feedback wallclock: Windows
runners take longer to provision and Python runs measurably slower on
Windows. Adding 6 jobs × 3 OSes = 18 jobs may slow PR turnaround even
when the bill is zero. The per-job matrix above keeps the fast-feedback
path (lint + typecheck) on a single OS for that reason.

Developer Mode default

GitHub-hosted windows-latest runners (currently windows-2022) have
Developer Mode enabled by default out of the box — verified against
the actions/runner-images manifest, has been true since 2021. So PR
#633's requires_symlinks marker will run the symlink tests on
Windows CI, not skip them, which is what we want.

Likely first-run failures

First Windows CI run will likely be red on more than just symlinks —
that's the point of adding the runner. Known surfaces to expect:

  • Hardcoded POSIX paths in tests. Path("/tmp/test.md") and
    similar appear in 9 test files: test_reranker_fastembed.py,
    test_uninstall_cmd.py, test_ask.py, test_indexing_engine.py
    (×4 sites), test_runtime_paths.py. Most are metadata-only
    (source_file=Path(...) passed without being opened), so some may
    pass on Windows by accident — worth triaging real bugs vs. cosmetic.
  • POSIX file-mode bits. tests/test_runtime_paths.py does
    mode=0o700 mkdir + mode=0o755 checks (4 sites). NTFS doesn't
    translate POSIX modes cleanly; the whole XDG_RUNTIME_DIR test class
    may need a Windows skip + a Windows-equivalent test.
  • mm web PID-file handling. _runtime_paths.py has POSIX-first
    XDG fallback to tempfile.gettempdir(), but the Windows fallback
    branch isn't exercised on CI today.
  • Line endings (CRLF). git config core.autocrlf true is the
    Windows default. Tests doing exact-byte comparison
    (e.g. assert (dest / "SKILL.md").read_bytes() == b"# foo skill\n"
    in test_install_skill_copies_tree) will break if checkout
    normalizes to CRLF. .gitattributes doesn't pin text eol=lf
    today — would need either pinning or test rewrite.
  • uv tool install shim path. README's mm: command not found
    troubleshooting tip mentions ~/.local/bin (POSIX-only) — the
    Windows shim path differs (%APPDATA%\uv\tools\...). Once Windows
    is CI-tested, the user-facing install flow is also worth covering.
  • Subprocess invocations that assume a POSIX shell.

Acceptance criteria

  • .github/workflows/ci.yml runs the test job on
    windows-latest (and macos-latest).
  • First-pass Windows-specific failures triaged: either fixed, or
    marked with the appropriate platform skip + a tracking
    sub-issue.
  • CI green on all matrix cells.
  • README / CONTRIBUTING reflects which platforms are now CI-tested
    (this is the moment Windows becomes a documented promise).

References

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions