Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/windows-contract.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Windows contract

on:
push:
branches:
- main
pull_request:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
contract:
name: Native Windows contract (Phase 0)
runs-on: windows-latest
timeout-minutes: 10

steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5

- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: "3.13"

- name: Install contract test dependencies
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
python -m pip install --upgrade pip
python -m pip install -r requirements-dev.txt

- name: Run documentation contract tests
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
python -m pytest -q tests/test_windows_support_docs.py

- name: Verify native Windows prerequisites
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
if ($PSVersionTable.PSVersion.Major -lt 7) {
throw "The native Windows contract requires PowerShell 7 or newer."
}
$git = Get-Command git -ErrorAction Stop
$python = Get-Command python -ErrorAction Stop
Write-Host "PowerShell: $($PSVersionTable.PSVersion)"
& $git.Source --version
& $python.Source --version

$manifest = Join-Path $PWD "base_manifest.yaml"
if (-not (Test-Path -LiteralPath $manifest -PathType Leaf)) {
throw "Expected Base manifest at $manifest"
}
python -c "from pathlib import Path; import yaml; payload = yaml.safe_load(Path('base_manifest.yaml').read_text(encoding='utf-8')); assert payload['project']['name'] == 'base'"

if (Get-Command bash -ErrorAction SilentlyContinue) {
Write-Host "Bash is present on the hosted runner, but this Phase 0 gate does not invoke it."
}
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,9 @@ Ubuntu/Debian support currently covers runtime checks, project diagnostics,
source-checkout validation, and apt-backed setup for the simple prerequisites
Base owns. Linux setup remains narrower than macOS setup and should stay behind
the platform-policy boundary described in [docs/linux-support.md](docs/linux-support.md).
Windows is out of scope.
Native Windows is planned but not supported yet. The staged target, compatibility
matrix, and explicit feature deferrals are documented in
[Native Windows Support Contract](docs/windows-support.md).

The macOS CI floor runs on GitHub's `macos-14` runner. Newer macOS runners may
be added for coverage, but the floor job should stay until Base intentionally
Expand Down
3 changes: 3 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ reference. The filename should answer "what is this about?"
dispatch order, public launchers, and runtime shell behavior.
- [Linux Support](linux-support.md) defines the Ubuntu/Debian runtime support,
apt-backed setup path, and bootstrap boundaries.
- [Native Windows Support Contract](windows-support.md) defines the proposed
PowerShell-first contract, staged parity model, compatibility matrix, and
boundaries for future native Windows work.
- [Runtime Environment](runtime-environment.md) is the canonical reference for
Base-managed environment variables, `~/.baserc`, and mutability rules.
- [Shell Startup Files](shell-startup.md) documents the marked Bash/Zsh dotfile
Expand Down
4 changes: 3 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ readiness, trust, onboarding, and handoff evidence needed to operate that repo
set through one CLI interface. The current implementation support contract
covers macOS plus narrow Ubuntu/Debian source-checkout runtime and apt-backed
setup paths. Broader Linux distribution support, WSL, and Windows are not in
scope today.
scope today. Native Windows has a separate staged proposal in
[Native Windows Support Contract](windows-support.md); it must not be treated as
supported until its native launcher and command subset have passed that contract.

The governing philosophy: **solve your own problem elegantly first**. Base is
built for a specific workflow: multiple peer Git repositories under a shared
Expand Down
1 change: 1 addition & 0 deletions docs/contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ before treating the fix as complete.
| Read-only inspection JSON | [Inspection JSON](inspection-json.md), [Command Quick Reference](command-reference.md) | `cli/bash/commands/basectl/tests/inspection-json.bats`, `cli/python/base_release/tests/test_engine.py`, [`base-cli/tests/test_inspection.py`](https://github.com/basefoundry/base-cli/blob/main/tests/test_inspection.py), `tests/test_stability_tiers_docs.py` | A scoped command emits prose or invalid JSON, changes the v1 envelope, loses finding/error semantics, or diverges from text-mode exit policy | CLI |
| Project metadata defaults | `.github/base-project.yml`, [GitHub Workflow](github-workflow.md), [Repository Baseline](repo-baseline.md) | `cli/python/base_github_projects/tests/`, `cli/bash/commands/basectl/tests/gh.bats`, `cli/bash/commands/basectl/tests/repo.bats` | Issue defaults, Project field options, or repo-visible Project configuration drift from the Base Project schema | Product |
| Canonical positioning documentation | [Product Requirements](product-requirements.md), [Product Assessment](product-assessment.md), [Why Base](why-base.md), and the canonical introduction surfaces | `tests/test_contract_hardening.py` | A canonical newcomer, contributor, or agent surface reintroduces retired product positioning or drops the accepted local-operating-contract thesis and outcome loop | Product |
| Native Windows support boundary | [Native Windows Support Contract](windows-support.md), `README.md`, `.github/workflows/windows-contract.yml` | `tests/test_windows_support_docs.py` | A public surface claims native Windows support before the launcher, command subset, and clean-install gates exist | Platform |

## Contract Check Runner

Expand Down
4 changes: 3 additions & 1 deletion docs/linux-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ Base does not ship a Debian package, own every project runtime dependency, or
claim support for every Linux distribution. Broader Linux families,
non-Debian WSL distributions, native Windows, GUI IDE setup on Linux, and
project-specific dependency ownership need separate product decisions and
platform adapters.
platform adapters. The proposed native Windows boundary is maintained in
[Native Windows Support Contract](windows-support.md); it is not a WSL2
extension of this Linux contract.

## Target Scope

Expand Down
3 changes: 2 additions & 1 deletion docs/product-requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ across every repository and external tool.

Base remains macOS-primary. Ubuntu/Debian source-checkout runtime and apt-backed
setup support are implemented, while broader Linux distribution support remains
intentionally narrow and Windows is not currently in scope.
intentionally narrow. Native Windows is not currently shipped; its proposed
staged contract is maintained in [Native Windows Support Contract](windows-support.md).

Major product work should improve the outcome loop. A broad command is not core
merely because Base can expose it.
Expand Down
2 changes: 2 additions & 0 deletions docs/technical-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ inventory -> prepare -> verify -> trust -> onboard -> hand off

The `basectl` CLI provides the execution surface for that loop, including setup,
diagnostics, project discovery, shell activation, test execution, and releases.
Native Windows is a planned PowerShell-first target, not a current support tier;
see [Native Windows Support Contract](windows-support.md) for the staged boundary.

> The repo you check out once per workspace so all other repos become easier to
> set up, test, and run.
Expand Down
150 changes: 150 additions & 0 deletions docs/windows-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Native Windows Support Contract

Status: proposal and implementation boundary; native Windows is not supported
by the current Base release.

This document defines the smallest credible path for bringing Base to native
Windows. It is intentionally a contract first. Git Bash and WSL2 are useful
development environments, but neither one is native Windows support and neither
one satisfies this proposal.

## Compatibility Matrix

| Environment | Current status | Runtime contract |
|---|---|---|
| macOS 14+ | Supported | Homebrew, Bash, Python, and Git |
| Ubuntu/Debian | Supported | Linux runtime with apt-backed setup |
| Ubuntu/Debian on WSL2 | Supported as Linux | `BASE_PLATFORM=linux-debian`, `BASE_HOST_ENV=wsl2` |
| Native Windows | Planned, not supported | PowerShell-first launcher and Windows-native adapters |
| Git Bash on Windows | Not a support tier | May run selected source scripts, but is not the native contract |

The README and release notes must keep native Windows in the planned column until
the Phase 1 acceptance criteria below pass on a clean `windows-latest` runner
and a clean supported Windows developer machine.

## Proposed Phase 1 Contract

The first native Windows slice targets Windows 11 22H2 or newer on x64 and
ARM64, with:

- PowerShell 7.4 or newer as the supported interactive shell;
- Git for Windows' native `git.exe` as the Git implementation;
- Python 3.10 through 3.13 from an installation managed by the user or the
documented Windows installer route;
- GitHub CLI only for commands that explicitly need GitHub access;
- no Bash executable, Bash dotfiles, Homebrew, apt, or WSL2 dependency;
- a process launcher that passes argument arrays to child processes and does not
reconstruct commands through a shell;
- no automatic profile mutation during install or first use.

`cmd.exe` is not a first-class interactive shell in Phase 1. It may invoke the
PowerShell entrypoint explicitly, but command completion and profile guidance
are PowerShell-specific until another shell contract is designed.

## Installation and State

The eventual clean-install route should use a versioned, signed Windows release
asset (MSI, MSIX, or an equivalently verifiable package) published with the
GitHub release. A network one-liner that downloads and executes an unpinned
script is not an acceptable installer contract.

The source checkout remains a supported contributor route. The release installer
must place the launcher and Base runtime in a versioned application location and
make updates replaceable without editing a user's project repositories.

Native Windows state is user-scoped:

| State | Location |
|---|---|
| Persistent Base state | `%LOCALAPPDATA%\Base` |
| Base cache | `%LOCALAPPDATA%\Base\Cache` |
| Temporary run data | `$env:TEMP` |
| Project checkout | User-selected workspace path; spaces are supported |

The implementation must not reuse the macOS `~/Library` or Linux `~/.cache`
locations on native Windows. A future state migration must be explicit and
backward-compatible.

## Initial Command Subset

Phase 1 is intentionally read-only or dry-run oriented. The supported subset is:

| Command surface | Phase 1 behavior |
|---|---|
| `basectl check` | Inspect the Windows runtime and report stable findings |
| `basectl doctor` | Explain readiness findings and recovery commands |
| `basectl projects list` | Discover projects under an explicit workspace path |
| `basectl projects status` | Report project state without mutation |
| `basectl projects manifest` | Parse and validate a project manifest |
| `basectl workspace status` | Report workspace membership and repository state |
| `basectl workspace check` | Run local workspace checks without credentials |
| `basectl workspace doctor` | Render workspace findings without mutation |
| `basectl setup --dry-run` | Describe planned setup without applying changes |
| `basectl gh auth status` | Report local GitHub CLI auth state when `gh` is installed |

Text and JSON output must preserve the existing inspection envelope and finding
semantics wherever the command is already a stable Base surface. Windows paths
may differ in representation, but they must remain unambiguous and parseable.

## Platform Boundary Rules

Windows-specific behavior belongs behind small platform adapters. The native
launcher and adapters own:

- `Path` and environment-variable resolution, including spaces and Unicode;
- process creation with `shell=False`-equivalent semantics;
- executable lookup and `.exe` resolution;
- UTF-8 text and CRLF/LF normalization at file boundaries;
- ACL-aware state-directory creation and permission diagnostics;
- the absence of POSIX executable bits and optional symlink privileges;
- Git's line-ending settings without rewriting repository-owned policy.

Command implementations must not scatter `if Windows` branches through their
business logic. The adapter should expose stable capabilities and return an
explicit unsupported result when a capability is not available.

The trust model remains unchanged: project-owned commands are still inspected
and explicitly approved before execution. Native Windows support must not weaken
that boundary just because process execution uses PowerShell.

## Staged Parity Model

| Phase | Outcome | Exit criteria |
|---|---|---|
| 0. Contract and CI | Make the target explicit and prevent documentation drift | This specification, visible matrix, and a Windows-hosted contract gate |
| 1. Native inspection | Ship the PowerShell launcher and read-only command subset | Clean install, `check`/`doctor`, manifest, workspace, and dry-run tests pass on Windows |
| 2. Setup and execution | Add Windows tool/runtime adapters and guarded project execution | Setup, trust, test/run, and failure recovery have native behavior and tests |
| 3. Developer parity | Add activation, demos, IDE integration, and release polish | Each feature has an explicit Windows adapter, docs, and hosted plus local validation |

The current repository is at Phase 0. This document and its CI gate do not claim
that a native Windows launcher or command subset has shipped. Phase 1 should be
implemented as a separate reviewable slice once the contract is approved.

## Explicit Deferrals

Until the required adapters exist, native Windows documentation must describe
these features as deferred:

- `basectl activate` and shell prompt integration;
- project `run`, `test`, `build`, and `demo` execution;
- manifest-declared setup mutation and package-manager adapters;
- IDE installation, extensions, and user settings;
- Bash completion, Bash startup sections, and `update-profile`;
- Homebrew and apt-backed artifacts;
- any claim that Git Bash or WSL2 is an equivalent runtime.

## Phase 1 Validation

The Windows job should run on `windows-latest` and prove the contract boundary
with no private credentials:

1. install the pinned Python test dependencies;
2. run the documentation/contract tests;
3. verify PowerShell, Python, and native Git discovery;
4. parse `base_manifest.yaml` and exercise the pure-Python manifest and workspace
readers against paths containing spaces;
5. validate that no test invokes Bash, WSL2, Homebrew, or apt.

The job is a Phase 0 gate until the native launcher exists. It must be renamed
and expanded when Phase 1 lands so the workflow cannot be mistaken for full
Windows support.
1 change: 1 addition & 0 deletions tests/test_contract_hardening.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ def test_contract_registry_rows_have_complete_enforcement_metadata() -> None:
"Read-only inspection JSON",
"Project metadata defaults",
"Canonical positioning documentation",
"Native Windows support boundary",
}
for row in rows:
assert row["Source of truth"], row
Expand Down
43 changes: 43 additions & 0 deletions tests/test_windows_support_docs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from pathlib import Path


REPO_ROOT = Path(__file__).resolve().parents[1]
WINDOWS_DOC = REPO_ROOT / "docs" / "windows-support.md"
README = REPO_ROOT / "README.md"
WORKFLOW = REPO_ROOT / ".github" / "workflows" / "windows-contract.yml"


def test_windows_contract_is_explicitly_provisional() -> None:
document = WINDOWS_DOC.read_text(encoding="utf-8")

assert "Status: proposal and implementation boundary" in document
assert "native Windows is not supported" in document
assert "Git Bash" in document
assert "WSL2" in document
assert "PowerShell 7.4" in document
assert "%LOCALAPPDATA%\\Base" in document


def test_windows_contract_defers_features_without_adapters() -> None:
document = WINDOWS_DOC.read_text(encoding="utf-8")

for feature in (
"basectl activate",
"project `run`, `test`, `build`, and `demo` execution",
"IDE installation",
"Bash completion",
"Homebrew and apt-backed artifacts",
):
assert feature in document


def test_public_surfaces_link_to_the_windows_contract_without_claiming_support() -> None:
document = WINDOWS_DOC.read_text(encoding="utf-8")
readme = README.read_text(encoding="utf-8")
workflow = WORKFLOW.read_text(encoding="utf-8")

assert "Native Windows Support Contract" in readme
assert "planned but not supported yet" in readme
assert "runs-on: windows-latest" in workflow
assert "Phase 0" in workflow
assert "mistaken for full" in document
Loading