Files
winutil/AGENTS.md
T
Sean (ANGRYxScotsman)andGitHub 1458327638 Containerize docs site tooling for security and update documentation (#4942)
* Containerize the docs site's npm tooling

Run Astro/Starlight dev, build, and preview commands through Docker
(docs/Dockerfile, docker-compose.yml, service winutil-astro) instead
of bare npm on the host, and document the required commands and
rationale in docs/README.md.

* Document Docker-only npm policy for agents

Add a Dependency Installs, Builds, And Dev Servers section to
AGENTS.md requiring docs/ tooling to run through Docker rather than
directly on the host, point SPEC.md's Docs Site section at the new
Dockerfile/docker-compose.yml, and renumber the remaining AGENTS.md
sections to stay sequential.

* Harden docs Docker dev environment

Tightened docs-container safety and clarified contributor workflow. The docs Docker image now switches to the non-root `node` user after setting ownership, and compose now binds Astro to `127.0.0.1` instead of all interfaces. Updated AGENTS and docs README instructions to explain the security boundary of the bind mount and to require rebuilding plus `docker compose down -v` after dependency changes so `node_modules` is reseeded correctly.

* Clarify docs secret handling in AGENTS

Updates AGENTS.md to tighten docs security guidance: secrets must not be stored anywhere under `docs/`, because `docs/.dockerignore` only affects image build context and does not protect files from the Docker Compose bind mount used for docs dev/build commands.

* Fix preview command to expose port in Docker

The previous preview command didn't expose the port outside the container. Adding --service-ports and binding to 0.0.0.0 makes the preview server accessible from the host.
2026-08-09 20:11:35 -05:00

14 KiB

AGENTS.md

Drop-in operating instructions for coding agents. Read this file before every task.

Working code only. Finish the job. Plausibility is not correctness.

SPEC.md in the repository root is the project contract — read it for what WinUtil is and how it's architected. This file covers how to work on it.

0. Non-Negotiables

These rules override everything else in this file when in conflict:

  1. Do not edit winutil.ps1 directly. It is generated build output (see SPEC.md's Build Model). Change source files and compile.
  2. Do not commit winutil.ps1. It is ignored locally and generated by GitHub Actions for releases.
  3. Never touch docs/src/content/docs/code-reference/tweaks/ or docs/src/content/docs/code-reference/features/. Both are auto-generated (see SPEC.md's Docs Site). Edit the source JSON (config/tweaks.json, config/feature.json) or the relevant PowerShell function file instead. Other hand-written pages under code-reference/ (e.g. architecture.mdx) are not touched by the generator and may be edited directly.
  4. Never fabricate. Do not invent file paths, function names, command output, test results, commit hashes, or API behavior. Read the file or run the command.
  5. Disagree when the premise is wrong. Say what is wrong before acting on it.
  6. Stop when genuinely ambiguous. If two interpretations would produce materially different diffs, ask before editing.
  7. Touch only what the task requires. No drive-by refactors, formatting sweeps, or unrelated cleanup.
  8. Verify before saying done. A plausible-looking diff is not proof.

1. Key Commands

  • Compile:
    .\Compile.ps1
    
  • Compile and run GUI:
    .\Compile.ps1 -Run
    
  • Install the supported Pester version (one-time). -SkipPublisherCheck is required because Windows ships an inbox Pester 3.4.0 that is catalog-signed, and PowerShell Gallery's Pester 5.8.0 is Authenticode-signed — Install-Module refuses the upgrade without it. This does not skip download integrity (still HTTPS + NuGet package hash verification); -Repository PSGallery pins the trusted source explicitly rather than relying on whatever repositories happen to be registered:
    Install-Module -Name Pester -RequiredVersion 5.8.0 -Repository PSGallery -Scope CurrentUser -Force -SkipPublisherCheck
    
  • Run tests:
    Import-Module Pester -RequiredVersion 5.8.0 -Force
    Invoke-Pester -Path 'pester/*.Tests.ps1' -Output Detailed -CI
    
  • Run Script Analyzer with project settings when available. If a locally compiled winutil.ps1 exists, delete it first — lint/PSScriptAnalyser.ps1 only excludes rules, not files, so -Recurse would also lint the generated script and produce noise against line numbers that don't map to any source file:
    Invoke-ScriptAnalyzer -Path . -Settings .\lint\PSScriptAnalyser.ps1 -Recurse
    
  • Docs site dev server (run from docs/; see Section 2 for why this goes through Docker):
    docker compose up winutil-astro
    
  • Docs site production build (run from docs/):
    docker compose run --rm winutil-astro npm run build
    

Prefer the narrowest useful verification while iterating. Use the full relevant check before finishing.

2. Dependency Installs, Builds, And Dev Servers

Given the current wave of npm/pnpm/yarn supply-chain worms (malicious postinstall/preinstall scripts, credential-stealing packages): never run npm/pnpm/yarn/npx directly on the host, full stop. The docs site (docs/) is the only npm-based project in this repo; always run its tooling inside Docker via docs/Dockerfile and docs/docker-compose.yml (service winutil-astro).

  • Never run npm install, npm run <script>, npx <pkg>, pnpm, or yarn directly on the host shell in docs/. Use docker compose run --rm winutil-astro <command> / docker compose up winutil-astro instead (see Section 1 for the exact commands).
  • If a task needs a new docs dependency, add it to docs/package.json yourself, then rebuild the image and drop the node_modules volume so it repopulates from the new image (run from docs/): docker compose build winutil-astro, then docker compose down -v. Docker only seeds a named volume from the image the first time it's created, so a plain rebuild silently leaves the old node_modules in place. Don't install packages on the host, even temporarily, "just to check something."
  • If Docker isn't available on the host, propose the install command for the current OS and wait for confirmation before running it — don't fall back to running npm on the host instead. If the daemon just isn't running (Docker is installed but not started), tell the user rather than trying to start it yourself.
  • Treat any postinstall/preinstall lifecycle script in a new dependency as worth flagging to the user before installing — summarize what it does.
  • Don't put real secrets anywhere under docs/. docs/.dockerignore only trims what docker build copies into the image — it does not affect the docker compose bind mount, which exposes the entire docs/ directory (including any .env file) inside the container for every dev/build/preview command (see the next bullet). There is no "keep it out unless mounted" middle ground here.
  • The container mounts docs/ as a volume, so file edits on the host are reflected inside the container immediately — no rebuild needed for normal code changes, only when docs/package.json/docs/package-lock.json change (see the rebuild-and-drop-volume steps above).
  • This Docker requirement is specific to docs/. The rest of the repo is PowerShell (Compile.ps1, Pester, Script Analyzer) and runs directly on the host per Section 1.

3. Source Of Truth

For changes that affect the compiled WinUtil script, make them only in the source files described in SPEC.md's Repository Layout — never in winutil.ps1 itself. If behavior changes require the compiled script to change, update the source files and run .\Compile.ps1 only to verify generation.

This scoping applies to compiled-script behavior only. Repository metadata — AGENTS.md, SPEC.md, CLAUDE.md/GEMINI.md/.github/copilot-instructions.md, .github/workflows/, and the root .gitignore — is edited directly when a task requires it, per the other sections of this file.

4. Before Editing

  • State the plan in one or two sentences before editing. For non-trivial work, include the verification you intend to run.
  • Read the files you will touch and the files that call them.
  • Match existing patterns even when a different greenfield design would be cleaner.
  • Surface assumptions when they affect behavior, compatibility, or user data.
  • If two approaches have meaningful tradeoffs, name them before choosing. Trivial tasks can proceed directly.

5. Coding Guidelines

  • Prefer the minimum code that solves the stated problem.
  • Keep PowerShell functions in one function file when practical, with the file name matching the primary function name.
  • Use approved PowerShell verb-noun names and follow the existing WPF / WinUtil naming conventions; keep UI event handler names aligned with XAML element names per SPEC.md's UI And Event Contract.
  • Use $sync for shared state and UI references, consistent with SPEC.md's Runtime Model.
  • Update WPF controls through the UI dispatcher when running work in a background runspace.
  • Keep config-driven features in JSON when they fit the existing schema instead of hard-coding lists in PowerShell; follow SPEC.md's Configuration Contract for required fields and key-renaming rules.
  • Preserve undo/original-state data for tweaks so users can reverse changes.
  • Do not add abstractions, configurability, hooks, or "future extensibility" unless the task needs them now.
  • Clean up orphans created by your own changes, such as unused variables or functions made obsolete by the edit.
  • Avoid broad formatting-only edits, especially in JSON config files, XAML, docs, and generated output.

6. Runtime And Safety Rules

  • WinUtil performs system-level Windows changes; treat registry, services, AppX removal, package manager, Windows Update, ISO, and unattended setup changes as high-risk (see SPEC.md's Safety Requirements).
  • Prefer existing helper functions for WinGet, Chocolatey, registry, services, progress, and UI updates.
  • Keep tweaks reversible where the schema supports it by including original values or original states.
  • Never modify a user's original ISO in-place; follow existing copy/mount/export patterns.
  • Avoid storing credentials, secrets, or machine-specific paths in repo files.
  • Preserve logging and user feedback patterns for long-running or destructive operations.

7. Surgical Changes

  • Do not improve adjacent code, comments, formatting, imports, or docs unless required.
  • Do not refactor working code because you are already in the file.
  • Do not delete pre-existing dead code unless asked; mention it in the summary if relevant.
  • Keep diffs reviewable. Every changed line should trace to the user's request.
  • If a change starts spreading across unrelated areas, pause and reassess the plan.

8. Verification

Define success in terms that can be checked, then check it.

  • For compile/build changes, run .\Compile.ps1.
  • For GUI behavior changes, run .\Compile.ps1 -Run when practical and verify the affected path manually.
  • For config changes, run the compile check and relevant Pester tests.
  • For function changes, run the relevant Pester tests or add/update focused tests when practical.
  • For docs-only changes, proofread the changed files and skip runtime tests unless docs generation is affected.
  • Read command output. Do not report tests as passing unless they actually passed.
  • If verification fails, fix the cause rather than weakening the test.

If a check cannot be run, say exactly why and what residual risk remains. See SPEC.md's Testing And CI for what GitHub Actions runs on every push.

9. Generated Files And Git Hygiene

  • Treat local winutil.ps1 changes as disposable compile output.
  • Never stage or commit winutil.ps1, binary/, or anything else ignored by the root .gitignore or docs/.gitignore — read those files rather than assuming. docs/public/ is tracked source for static assets, not generated output.
  • Do not remove .gitignore rules that keep generated artifacts out of Git.
  • Before finishing, check git status --short and separate your changes from pre-existing user changes.
  • Do not revert user changes unless explicitly asked.
  • Commit messages, when requested, should be descriptive: short subject under 72 characters, body explaining why when needed.
  • When committing, split changes into small, logical commits rather than one large commit, so each commit's diff is reviewable as a single group of related changes.

10. Documentation Expectations

  • Update docs/src/content/docs/guides/ when user-facing behavior changes.
  • Update docs/src/content/docs/code-reference/architecture.mdx and other hand-written developer docs when architecture, build flow, config schema, or contribution workflow changes — but never hand-edit the auto-generated code-reference/tweaks/ or code-reference/features/ subfolders (see Non-Negotiables).
  • Keep sidebar entries in docs/astro.config.mjs in sync with page slugs (see SPEC.md's Docs Site).
  • Keep README changes brief and high-level.
  • Put detailed user and developer documentation under docs/.
  • Keep SPEC.md aligned with project/architecture changes, and this file aligned with process changes.

11. Communication Style

  • Be direct and concise. Start with the answer or action.
  • No flattery, filler, ceremonial closings, or fake certainty.
  • Use bullets only when they improve scanning.
  • Report what changed, how it was verified, and anything not done.
  • If the user asks for a review, lead with findings and file/line references.

12. When To Ask

Ask before proceeding when:

  • The request has two plausible interpretations and the choice materially changes behavior or files touched.
  • The change affects release generation, generated artifacts, migrations, or high-risk Windows behavior in a way the user did not specify.
  • You need credentials, secrets, production resources, or access you do not have.
  • The user's stated goal conflicts with the literal request.

Proceed without asking when:

  • The task is trivial and reversible.
  • Ambiguity can be resolved by reading the code or running a local command.
  • The user already answered the question in this session.

13. Project Learnings

When the user corrects an agent approach, add or tighten one concrete rule here before ending the session. Keep this section short and prune rules that no longer matter.

  • Keep winutil.ps1 generated-only: change source files, compile to verify, and never stage the generated script.
  • Keep WinUtil runtime logging in the existing timestamped %LocalAppData%\winutil\logs\winutil_*.log session file; do not create a separate root winutil.log.
  • Import Pester 5.8.0 before running tests so Invoke-Pester -Output Detailed -CI does not resolve to Windows' inbox Pester 3.4.0.
  • Keep package install/uninstall process launches simple unless explicitly requested; do not add a separate stdout/stderr process logging helper for winget or Chocolatey.
  • When the active log file is owned by Start-Transcript, do not call Add-Content against that file; write to host output so the transcript captures the line in the same log file without recording a terminating-error diagnostic.
  • Keep UI helpers such as Invoke-WPFUIThread and Set-WinUtilTweaksProgressIndicator safe to call without a window; the -Preset and -Config paths run the workflows before the form is created and before PresentationCore is loaded.
  • Log install/uninstall package names and package-manager IDs before queuing background runspace work; do not rely on runspace host output for the package identity.
  • For Win11 Creator, start each new ISO modification in a fresh WinUtil_Win11ISO_* temp directory; existing-work detection is only for resuming/exporting already modified media.
  • For Win11 Creator driver injection, keep offline WIM servicing to one mount, one /Add-Driver, and one commit; do not export editions or run unrelated WIM cleanup, and reject damaged metadata before ISO export.
  • For Script Analyzer cleanup, fix actionable source warnings first and do not globally suppress accepted convention warnings such as plural names, ShouldProcess on UI helpers, $global:sync, or compile-time cross-file false positives.
  • For DNS DHCP reset, keep the cmdlet reset and explicitly set IPv4 and IPv6 DNS source to DHCP.