Centralize agent instructions in SPEC (#4912)

* Centralize agent instructions in SPEC

Move the full coding-agent contract and repository guidance from `AGENTS.md` into `SPEC.md`, and reduce `AGENTS.md` to a simple pointer to the canonical instructions. Add lightweight `CLAUDE.md`, `GEMINI.md`, and `.github/copilot-instructions.md` files so different assistants consistently bootstrap through the same repo-specific guidance.

* Clarify auto-generated docs path scope in SPEC

Narrowed rule #3 to specify exact auto-generated subdirectories (tweaks/ and features/) rather than the entire code-reference/ directory, and clarified that other hand-written pages (e.g. architecture.mdx) may be edited directly.

* Remove archived docs from gitignore

Drop the old `docs-old` Hugo ignore rules from `.gitignore`, reflecting that the archived docs build artifacts no longer need special handling there.

* Add local env files to docs .gitignore

Add .env.local and .env.*.local patterns to prevent local environment files from being committed.

* Clarify test and git hygiene guidance

Update `SPEC.md` to run Pester in CI mode and tighten repository hygiene instructions around ignored files. The git guidance now points contributors to the actual `.gitignore` files and clarifies that `docs/public/` contains tracked static assets rather than generated output.

* Split agent workflow from project spec

Move repository working instructions into `AGENTS.md` and refocus `SPEC.md` on the stable WinUtil project contract. This separates agent-specific guidance from architecture, build, runtime, docs, testing, and release details so both documents have clearer ownership.

* docs: clarify Pester, ScriptAnalyzer, and source-of-truth rules

Expand AGENTS.md with context on why -SkipPublisherCheck is needed for Pester installation, why winutil.ps1 should be deleted before running ScriptAnalyzer, and clarify that the source-of-truth rule applies only to compiled-script behavior — repository metadata files are edited directly.

* Clarify Pester install command and -SkipPublisherCheck reason

Expands the explanation for why -SkipPublisherCheck is needed (catalog-signed vs Authenticode-signed), clarifies it does not skip download integrity, and adds -Repository PSGallery to pin the trusted source explicitly.
This commit is contained in:
Sean (ANGRYxScotsman)
2026-08-04 15:29:49 -05:00
committed by GitHub
parent a0142ace72
commit b096aaa5e5
7 changed files with 122 additions and 134 deletions
+64 -58
View File
@@ -1,10 +1,37 @@
# SPEC.md
## Project Contract
Project contract for WinUtil — what the project is, how it's built, and how it runs. Written for anyone, human or AI, who needs to understand the project itself.
WinUtil is a Windows PowerShell utility with a WPF interface. The repository is maintained as modular source files, but the released artifact is a single generated `winutil.ps1` script.
`AGENTS.md` in the repository root points here for these facts, and separately covers how an agent should behave while working in this repo. This file does not change based on who's reading it.
The compiled `winutil.ps1` is not source code for editing or review. It is generated by `Compile.ps1` and produced during release automation. All durable changes must be made to the source files that feed the compiler.
## Project Context
WinUtil is a Windows PowerShell utility with a WPF interface. The repository is maintained as modular source, but the distributed artifact is one compiled PowerShell script.
### Stack
- Language: Windows PowerShell / PowerShell.
- UI: WPF via `xaml/inputXML.xaml`.
- Configuration: JSON files under `config/`.
- Tests: Pester tests under `pester/`.
- Lint: PowerShell Script Analyzer with settings in `lint/PSScriptAnalyser.ps1`.
- Docs: Astro + Starlight site under `docs/`, built independently of `Compile.ps1` (its own `package.json`/`node_modules`).
- Release artifact: generated root `winutil.ps1`.
### Repository Layout
- `Compile.ps1`: build script that creates `winutil.ps1`.
- `scripts/start.ps1`: startup/bootstrap segment used at the beginning of the compiled script.
- `scripts/main.ps1`: main entrypoint appended at the end of the compiled script.
- `functions/public/`: public/UI-facing PowerShell functions.
- `functions/private/`: internal helper PowerShell functions.
- `config/`: JSON configuration consumed at compile time and embedded into `$sync.configs`.
- `xaml/inputXML.xaml`: WPF UI markup embedded into the compiled script.
- `tools/autounattend.xml`: unattended setup XML embedded for Windows ISO workflows.
- `pester/`: Pester tests for config and function checks.
- `lint/PSScriptAnalyser.ps1`: PowerShell Script Analyzer settings.
- `docs/`: Astro + Starlight documentation site, with its own `package.json` and build independent of `Compile.ps1`.
- `winutil.ps1`: ignored generated build artifact.
## Goals
@@ -21,85 +48,64 @@ The compiled `winutil.ps1` is not source code for editing or review. It is gener
- The GUI is not a separate packaged desktop application in this repository's normal release path.
- Generated files should not be reviewed as source changes.
## Repository Layout
## Build Model
- `Compile.ps1`: build script that creates `winutil.ps1`.
- `scripts/start.ps1`: startup/bootstrap segment used at the beginning of the compiled script.
- `scripts/main.ps1`: main entrypoint appended at the end of the compiled script.
- `functions/public/`: public/UI-facing PowerShell functions.
- `functions/private/`: internal helper PowerShell functions.
- `config/`: JSON configuration consumed at compile time and embedded into `$sync.configs`.
- `xaml/inputXML.xaml`: WPF UI markup embedded into the compiled script.
- `tools/autounattend.xml`: unattended setup XML embedded for Windows ISO workflows.
- `pester/`: Pester tests for config and function checks.
- `lint/PSScriptAnalyser.ps1`: PowerShell Script Analyzer settings.
- `docs/`: Hugo documentation site.
- `winutil.ps1`: ignored generated build artifact.
`Compile.ps1` combines the repository sources into `winutil.ps1` in this order:
## Compile Specification
1. Read `scripts/start.ps1` and replace `#{replaceme}` with the current `yy.MM.dd` build date.
2. Append every file under `functions/` recursively.
3. Convert each `config/*.json` file into embedded `$sync.configs` objects.
4. Special-case `config/applications.json` so keys receive the `WPFInstall` prefix in compiled config.
5. Embed `xaml/inputXML.xaml` into `$inputXML`.
6. Embed `tools/autounattend.xml` into `$WinUtilAutounattendXml`.
7. Append `scripts/main.ps1`.
8. Write the result to root `winutil.ps1`.
`Compile.ps1` must produce a standalone root `winutil.ps1` by combining all required project files.
The compile flow is:
1. Initialize shared state with `$sync = [Hashtable]::Synchronized(@{})` and `$sync.configs = @{}`.
2. Read `scripts/start.ps1`.
3. Replace `#{replaceme}` in startup code with the current `yy.MM.dd` build date.
4. Append raw content from all files under `functions/` recursively.
5. For every file in `config/`, parse JSON and embed it into `$sync.configs.<basename>`.
6. Special-case `config/applications.json` so application keys are emitted with the `WPFInstall` prefix.
7. Embed `xaml/inputXML.xaml` as `$inputXML`.
8. Embed `tools/autounattend.xml` as `$WinUtilAutounattendXml`.
9. Append `scripts/main.ps1`.
10. Write the combined script to `winutil.ps1`.
11. If `-Run` is supplied, execute the generated script.
The generated script must have everything it needs from repository sources embedded or appended by this process.
Because the final script is concatenated, code cannot rely on runtime module imports or source-relative dot-sourcing unless the compiled script will also contain the required code/data.
## Runtime Model
- WinUtil runs in PowerShell on Windows and uses WPF for the UI.
- Shared mutable state is stored in `$sync`, including configs, UI element references, runspace state, selections, and progress.
- Long-running operations should use runspaces or existing async patterns so the UI remains responsive.
- UI updates from background work must be dispatched back to the WPF UI thread.
- Declarative features such as apps, tweaks, presets, DNS providers, and navigation should stay in `config/*.json` unless code is required.
- Long-running operations use runspaces or existing async patterns so the UI remains responsive.
- UI updates from background work are dispatched back to the WPF UI thread.
- Declarative features such as apps, tweaks, presets, DNS providers, and navigation stay in `config/*.json` unless code is required.
## UI And Event Contract
- UI layout lives in `xaml/inputXML.xaml`.
- Named WPF controls are discovered and stored in `$sync`.
- Button/action wiring follows existing naming conventions, where an element named like `WPFThingButton` maps to a function named like `Invoke-WPFThingButton`.
- When adding controls, ensure the XAML name, config key, and PowerShell function names line up with the existing event system.
- Button/action wiring follows a naming convention: an element named like `WPFThingButton` maps to a function named like `Invoke-WPFThingButton`.
## Configuration Contract
Config files must remain valid JSON and compile cleanly through `ConvertFrom-Json`.
`config/applications.json` defines installable applications. Each application entry should include the fields expected by tests and UI code, such as package manager IDs, category, display content, description, and link.
`config/tweaks.json` defines Windows tweaks. Registry and service changes should include original values or original states when applicable so undo workflows can restore user systems.
Preset and navigation files should reference valid config keys. Avoid renaming config keys unless all presets, UI references, docs, and code paths are updated together.
- Config files must remain valid JSON and compile cleanly through `ConvertFrom-Json`.
- `config/applications.json` defines installable applications; each entry includes the fields expected by tests and UI code, such as package manager IDs, category, display content, description, and link.
- `config/tweaks.json` defines Windows tweaks; registry and service changes include original values or original states when applicable so undo workflows can restore user systems.
- Preset and navigation files reference valid config keys. Renaming a config key requires updating all presets, UI references, docs, and code paths together.
## Safety Requirements
- Registry, service, package manager, Windows Update, AppX removal, and ISO operations can affect the host system. Changes must be explicit, reversible where practical, and consistent with existing logging and confirmation patterns.
- Tweak changes should include undo metadata when the schema supports it.
- Package installation should prefer existing WinGet and Chocolatey helper functions.
- ISO workflows must not modify the user's original ISO file; they should work on copied/mounted content following existing patterns.
- Registry, service, package manager, Windows Update, AppX removal, and ISO operations affect the host system and are treated as high-risk.
- Tweak changes include undo metadata when the schema supports it, so changes stay reversible.
- ISO workflows never modify the user's original ISO file; they work on copied/mounted content.
## Docs Site (Astro)
- `docs/` is an Astro + Starlight site, independent of `Compile.ps1`'s build (its own `package.json`/`node_modules`, deployed via the `docs.yaml` GitHub Actions workflow to GitHub Pages).
- Pages live under `docs/src/content/docs/` (`.mdx`), organized into `guides/`, `code-reference/`, plus top-level pages like `faq.mdx`, `knownissues.mdx`, `contributing.mdx`, `index.mdx`.
- `docs/src/content/docs/code-reference/tweaks/` and `.../features/` are auto-generated by `tools/devdocs-generator.ps1` from `config/tweaks.json`/`config/feature.json` and the relevant PowerShell function files. Other pages under `code-reference/` (e.g. `architecture.mdx`) are hand-written and untouched by the generator.
- Sidebar entries in `docs/astro.config.mjs` must match actual page slugs under `docs/src/content/docs/`.
- `docs/public/` is tracked source for static assets (favicons, etc.), not generated output. Generated/ignored paths are listed in `docs/.gitignore` (`dist/`, `.astro/`, `node_modules/`, local env files).
## Testing And CI
Expected validation for source changes:
- `.\Compile.ps1` verifies the compiler can generate `winutil.ps1`.
- `.\Compile.ps1 -Run` compiles and launches the generated utility for manual GUI verification.
- `Install-Module -Name Pester -RequiredVersion 5.8.0 -Scope CurrentUser -Force -SkipPublisherCheck` installs the supported Pester version.
- `Import-Module Pester -RequiredVersion 5.8.0 -Force; Invoke-Pester -Path 'pester/*.Tests.ps1' -Output Detailed -CI` runs the Pester suite.
- GitHub Actions also runs a compile check and PowerShell Script Analyzer with `lint/PSScriptAnalyser.ps1`.
The generated `winutil.ps1` may appear locally after compile. It remains ignored build output and must not be committed.
- Pester 5.8.0 runs the suite under `pester/*.Tests.ps1`. GitHub Actions (`unittests.yaml`) installs Pester 5.8.0 fresh and runs with `-CI`, which produces `testResults.xml` and exits non-zero on failure.
- GitHub Actions also runs PowerShell Script Analyzer with `lint/PSScriptAnalyser.ps1` on every push.
- The generated `winutil.ps1` may appear locally after compile. It remains ignored build output (see root `.gitignore`) and must not be committed.
## Release Artifact
GitHub Actions is responsible for producing the release `winutil.ps1` from repository sources. A release should be considered valid only if the generated script came from the compile process, not from direct manual edits to `winutil.ps1`.
GitHub Actions is responsible for producing the release `winutil.ps1` from repository sources. A release is considered valid only if the generated script came from the compile process, not from direct manual edits to `winutil.ps1`.