From 3a171f09ff427ff8959984964f5c336a60c15784 Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Tue, 18 Aug 2026 18:41:28 -0400 Subject: [PATCH 1/5] chore(aim): sync instruction modules to AIM 0.11.0 Was on none. Brings in the Pester section, which documents that Set-ItResult ends the It block so a trailing return is unreachable. --- instructions/agent-workflow.instructions.md | 4 +- instructions/contributing.instructions.md | 2 +- instructions/git-workflow.instructions.md | 97 ++++-- instructions/github-cli.instructions.md | 10 +- instructions/markdown.instructions.md | 4 +- instructions/powershell.instructions.md | 340 +++++++++++++++++--- instructions/releases.instructions.md | 25 +- instructions/shorthand.instructions.md | 1 + instructions/testing.instructions.md | 17 +- instructions/update.instructions.md | 83 ++++- 10 files changed, 473 insertions(+), 110 deletions(-) diff --git a/instructions/agent-workflow.instructions.md b/instructions/agent-workflow.instructions.md index 3ce2032..efc3f66 100644 --- a/instructions/agent-workflow.instructions.md +++ b/instructions/agent-workflow.instructions.md @@ -72,8 +72,8 @@ This builds trust and catches misunderstandings early. ## When in Doubt 1. **Ask for clarification** - Better to ask than implement incorrectly -1. **Check existing code** - Follow established patterns in the codebase -1. **Keep it simple** - The simplest solution that works is usually best +2. **Check existing code** - Follow established patterns in the codebase +3. **Keep it simple** - The simplest solution that works is usually best ## Post-Task Protocol diff --git a/instructions/contributing.instructions.md b/instructions/contributing.instructions.md index c1e407d..3c03a57 100644 --- a/instructions/contributing.instructions.md +++ b/instructions/contributing.instructions.md @@ -56,7 +56,7 @@ Follow existing patterns in the repository: **For new instruction files:** -- Place in `instructions/` folder +- Place in `instruction-templates/` folder - Use `.instructions.md` extension - Include required YAML frontmatter diff --git a/instructions/git-workflow.instructions.md b/instructions/git-workflow.instructions.md index 7e1fdb1..9c3d96c 100644 --- a/instructions/git-workflow.instructions.md +++ b/instructions/git-workflow.instructions.md @@ -7,39 +7,81 @@ description: 'Git workflow conventions including branching, commits, and pull re Guidelines for consistent Git usage across repositories. +## Working on Branches + +**Agents must always work on branches, never directly on main.** + +Before starting any work: + +1. Create a branch from `main` using the naming conventions below +2. Make changes in small, logical commits +3. Push the branch and create a pull request +4. Wait for CI checks and address any review feedback +5. Report status and wait for instructions before merging + +This ensures all changes go through review and CI validation before reaching the main branch. + ## Branch Naming -Use descriptive, lowercase branch names with hyphens: +Use descriptive, lowercase branch names with hyphens. + +### Basic Format ```text / ``` -**Types:** +### Format with Ticket Numbers + +When using project management tools, include the ticket identifier: + +```text +/- +``` + +### Branch Types -- `feature/` - New functionality -- `fix/` - Bug fixes -- `docs/` - Documentation only -- `refactor/` - Code restructuring -- `test/` - Adding or updating tests -- `chore/` - Maintenance tasks +| Prefix | Purpose | Example | +| ----------- | ------------------------------------ | ------------------------------------ | +| `feature/` | New functionality | `feature/user-authentication` | +| `bugfix/` | Bug fixes | `bugfix/login-validation-error` | +| `hotfix/` | Urgent production patches | `hotfix/security-vulnerability` | +| `release/` | Release preparation | `release/v1.2.0` | +| `docs/` | Documentation only | `docs/api-documentation` | +| `refactor/` | Code restructuring | `refactor/database-queries` | +| `test/` | Adding or updating tests | `test/payment-integration` | +| `chore/` | Maintenance tasks | `chore/update-dependencies` | -**Examples:** +### Examples with Ticket Numbers ```text -feature/user-authentication -fix/login-validation-error -docs/api-documentation -refactor/database-queries -test/payment-integration -chore/update-dependencies +feature/PROJ-123-add-user-authentication +bugfix/PROJ-456-fix-login-validation +hotfix/PROJ-789-patch-security-issue ``` -**Avoid:** +### Best Practices + +- **Be descriptive**: Names should reflect the branch's purpose or task +- **Be concise**: Keep names brief but meaningful +- **Be consistent**: Follow the same conventions across the team +- **Use lowercase**: Avoid mixed case for cross-platform compatibility +- **Use hyphens**: Separate words with hyphens, not underscores or spaces + +### Technical Constraints + +Avoid the following in branch names: + +- Dots at the start of the name +- Trailing slashes +- Reserved Git names (`HEAD`, `FETCH_HEAD`) +- Spaces or special characters (except hyphens and forward slashes) + +### Avoid -- Spaces or special characters - Overly long names - Generic names like `fix`, `update`, `changes` +- Names without context or purpose ## Commit Messages @@ -94,9 +136,9 @@ asdfasdf ### Before Creating a PR 1. Ensure your branch is up to date with the base branch -1. Run tests locally and verify they pass -1. Review your own changes first -1. Remove debugging code and console logs +2. Run tests locally and verify they pass +3. Review your own changes first +4. Remove debugging code and console logs ### PR Title @@ -140,6 +182,13 @@ None - Large changes should be split into logical commits - If a PR is too large, consider breaking it into smaller PRs +### After Creating a PR + +1. **Monitor CI**: Wait for CI checks to complete and verify they pass +2. **Check for comments**: Review the PR for any feedback or requested changes +3. **Address feedback**: Make additional commits to address review comments +4. **Report status**: Report the PR status to the user and wait for instructions before merging + ## Branching Strategy ### Default Branch @@ -158,10 +207,10 @@ None ### Feature Branches 1. Create feature branch from `main` -1. Make changes in small, logical commits -1. Push branch and create PR -1. After review and approval, merge to `main` -1. Delete feature branch after merge +2. Make changes in small, logical commits +3. Push branch and create PR +4. After review and approval, merge to `main` +5. Delete feature branch after merge ### Keeping Branches Updated diff --git a/instructions/github-cli.instructions.md b/instructions/github-cli.instructions.md index 950373e..347a024 100644 --- a/instructions/github-cli.instructions.md +++ b/instructions/github-cli.instructions.md @@ -164,9 +164,15 @@ gh run view --log-failed ### Creating Releases +Use `--notes-file` (write notes to a temporary file first) rather than `--notes` to avoid +escaping issues with backticks, backslashes, and quotes. For project releases, the rules in +`releases.instructions.md` take precedence over these examples. + ```bash -# Create release from tag -gh release create v1.0.0 --title "Version 1.0.0" --notes "Release notes" +# Create release from tag (write notes to a file first to avoid escaping issues) +printf '## Highlights\n\n- Your release notes here\n' > release-notes.md +gh release create v1.0.0 --title "Version 1.0.0" --notes-file release-notes.md +rm release-notes.md # Create release with auto-generated notes gh release create v1.0.0 --generate-notes diff --git a/instructions/markdown.instructions.md b/instructions/markdown.instructions.md index 90bc1bc..430da58 100644 --- a/instructions/markdown.instructions.md +++ b/instructions/markdown.instructions.md @@ -26,7 +26,7 @@ Consistent Markdown formatting for documentation files. ## Lists - Use `-` for unordered lists -- Use `1.` for ordered lists (let markdown handle numbering) +- Use sequential numbering for ordered lists (`1.`, `2.`, `3.`, etc.) - Use 2 spaces for nested list indentation ```markdown @@ -47,6 +47,8 @@ Text after list. - Always specify language for fenced code blocks - Ensure closing triple backticks are on their own line - No trailing whitespace after closing backticks +- Code inside fenced blocks should follow the conventions of the relevant language's instruction + file (e.g., PowerShell snippets follow `powershell.instructions.md`) ```javascript // JavaScript code here diff --git a/instructions/powershell.instructions.md b/instructions/powershell.instructions.md index 1331430..cd49306 100644 --- a/instructions/powershell.instructions.md +++ b/instructions/powershell.instructions.md @@ -7,16 +7,53 @@ description: 'PowerShell coding standards and best practices' Style rules for PowerShell code based on Microsoft guidelines and community standards. +## Common Mistakes to Avoid + +**IMPORTANT**: These are frequent violations that MUST be avoided: + +1. **Plural nouns in function names** - ALWAYS use singular nouns regardless of how many items the + function returns. Use `Get-User` not `Get-Users`, `Get-Item` not `Get-Items`. + ## Function Structure 1. Always start functions with `[CmdletBinding()]` attribute -1. Always include explicit `param()` block -1. Use `process {}` block when accepting pipeline input -1. For system-modifying cmdlets, use `[CmdletBinding(SupportsShouldProcess)]` -1. Document output types with `[OutputType([TypeName])]` attribute -1. Include comment-based help for all functions +2. Always include explicit `param()` block +3. Use `process {}` block when accepting pipeline input +4. For system-modifying cmdlets, use `[CmdletBinding(SupportsShouldProcess)]` +5. Document output types with `[OutputType([TypeName])]` attribute +6. Include comment-based help for all functions +7. Do not define nested functions inside other functions; define helper functions at module or + script scope ```powershell +# Bad - nested function +function Get-Data { + [CmdletBinding()] + param() + + function Format-Result { + param($Value) + # Helper logic + } + + $result = Get-RawData + Format-Result -Value $result +} + +# Good - separate functions at module/script scope +function Format-Result { + [CmdletBinding()] + [OutputType([psobject])] + param( + [Parameter(Mandatory)] + [ValidateNotNull()] + [psobject] + $Value + ) + # Helper logic +} + + function Get-Data { [CmdletBinding()] [OutputType([hashtable])] @@ -61,6 +98,7 @@ function Get-Setting { [OutputType([PSCustomObject])] param( [Parameter(Mandatory)] + [ValidateNotNull()] [hashtable] $Configuration ) @@ -81,14 +119,15 @@ function Get-Setting { ## Naming Conventions 1. Use approved PowerShell verbs only (verify with `Get-Verb`) -1. Use singular nouns for function names (`Get-Item` not `Get-Items`) -1. Use PascalCase for function names and parameters -1. Use camelCase for local variables (`$userName`, `$itemCount`) -1. Use descriptive variable names that indicate purpose -1. Use full cmdlet names, never aliases (`Get-Process` not `gps`) +2. Use singular nouns for function names (`Get-Item` not `Get-Items`) +3. Use PascalCase for function names and parameters +4. Use camelCase for local variables (`$userName`, `$itemCount`) +5. Use descriptive variable names that indicate purpose +6. Use full cmdlet names, never aliases (`Get-Process` not `gps`) ```powershell # Good - descriptive variable names +$backupPath = 'C:\Backups' $backupFiles = Get-ChildItem -Path $backupPath -Filter '*.bak' $activeUsers = Get-ADUser -Filter { Enabled -eq $true } @@ -97,12 +136,57 @@ $files = Get-ChildItem -Path $backupPath -Filter '*.bak' $users = Get-ADUser -Filter { Enabled -eq $true } ``` +### Path vs Directory Naming + +Use the appropriate suffix to indicate what the variable holds: + +- Use `Path` for any path string (file or folder) +- Reserve `Directory` for directory objects (e.g., `[System.IO.DirectoryInfo]`) or bare folder names + +```powershell +# Good - Path suffix for path strings +$configurationPath = Join-Path -Path $PSScriptRoot -ChildPath 'config.json' +$outputPath = Join-Path -Path $PSScriptRoot -ChildPath 'results' +$backupPath = 'C:\Backups' + +# Good - Directory suffix for a directory object +$logDirectory = [System.IO.DirectoryInfo]::new('C:\Logs') + +# Bad - Directory suffix on a path string +$outputDirectory = 'C:\App\results' +``` + ## Parameters -1. Use full parameter names in scripts and functions -1. Always use quotes around string parameter values -1. Include validation on every parameter -1. Place each component on its own line +1. Name parameters on calls that pass two or more arguments; a single-argument call may stay + positional. Naming disambiguates which value maps to which parameter when there are several; + with one argument there is nothing to disambiguate, so naming it only adds noise. +2. Always use quotes around string parameter values +3. Include validation on every parameter +4. Place each component on its own line + +```powershell +# Good - 2+ arguments: name them (no positional guessing) +Get-ChildItem -Path 'C:\Logs' -Filter '*.log' -Recurse +Copy-Item -Path $sourcePath -Destination $destinationPath + +# Good - single argument: positional is fine +Test-Path $configurationPath +Import-Module $modulePath + +# Avoid - naming the only argument adds noise without removing ambiguity +Test-Path -Path $configurationPath +``` + +```powershell +# Good - string parameter values are quoted +Get-Process 'powershell' +Get-ChildItem -Path 'C:\Program Files' -Filter '*.txt' + +# Bad - bare string parameter values +Get-Process powershell +Get-ChildItem -Path C:\Program Files -Filter *.txt +``` ```powershell function Get-UserData { @@ -129,11 +213,11 @@ function Get-UserData { ## Formatting 1. Opening brace `{` at end of line, closing brace `}` on new line -1. Use 4 spaces per indentation level -1. Maximum line length: 115 characters -1. Use splatting for long parameter lists -1. Two blank lines before function definitions -1. One blank line at end of file +2. Use 4 spaces per indentation level +3. Maximum line length: 115 characters +4. Use splatting for long parameter lists +5. Two blank lines before function definitions +6. One blank line at end of file ```powershell function Test-Code { @@ -157,39 +241,95 @@ function Test-Code { } # Good - splatting for readability -$parameters = @{ +$invokeRestMethodParameters = @{ Uri = 'https://api.example.com/endpoint' Method = 'Post' Headers = $headers Body = $body } -Invoke-RestMethod @parameters +Invoke-RestMethod @invokeRestMethodParameters +``` + +## Line Continuation + +1. Do not use backtick (`` ` ``) line continuation +2. Do not use semicolons (`;`) to chain multiple statements on one line +3. Prefer splatting (`@copyItemParameters`) for long parameter lists +4. Use natural continuation inside `()`, `@{}`, or `@()` when grouping expressions or collections +5. Place each hashtable element on its own line in multi-line hashtables +6. Pipelines continue without backticks when the line ends with `|` + +```powershell +# Good - splatting for long parameter lists +$copyItemParameters = @{ + Path = $sourcePath + Destination = $destinationPath + Recurse = $true + Force = $true +} +Copy-Item @copyItemParameters + +# Good - pipeline continues across lines +Get-ChildItem -Path $sourceDirectory -Recurse | + Where-Object { $_.Length -gt 1MB } | + Sort-Object -Property 'Length' -Descending + +# Good - natural continuation inside parentheses +$summaryMessage = ( + "Processed $successCount of $totalCount records. " + + "Skipped $skipCount records. " + + "Encountered $errorCount errors." +) + +# Good - for-loop semicolons are syntactic, not statement chaining +for ($i = 0; $i -lt 10; $i++) { + Write-Output -InputObject $i +} + +# Good - hashtable with each element on its own line +$webRequestOptions = @{ + Name = 'Value' + Size = 100 +} + +# Bad - backtick line continuation +Copy-Item -Path $sourcePath ` + -Destination $destinationPath ` + -Recurse ` + -Force + +# Bad - semicolons chaining statements +Import-Module -Name 'PSReadLine'; Set-PSReadLineOption -EditMode 'Emacs' + +# Bad - hashtable elements chained with semicolons on one line +$webRequestOptions = @{ Name = 'Value'; Size = 100 } ``` ## Paths and File System 1. Use `$PSScriptRoot` for script-relative paths -1. Use `$Env:UserProfile` or `$HOME` instead of `~` -1. Use `Join-Path` to construct paths +2. Use `$Env:UserProfile` or `$HOME` instead of `~` +3. Use `Join-Path` to construct paths ```powershell # Good -$configPath = Join-Path -Path $PSScriptRoot -ChildPath 'config.json' -$userPath = Join-Path -Path $Env:UserProfile -ChildPath 'Documents' +$configurationPath = Join-Path -Path $PSScriptRoot -ChildPath 'config.json' +$documentsPath = Join-Path -Path $Env:UserProfile -ChildPath 'Documents' # Bad -$configPath = '.\config.json' -$userPath = '~\Documents' +$configurationPath = '.\config.json' +$documentsPath = '~\Documents' ``` ## Error Handling 1. Use `-ErrorAction 'Stop'` for cmdlets within try/catch -1. Immediately copy `$_` in catch blocks before other commands +2. Immediately copy `$_` in catch blocks before other commands ```powershell +$filePath = 'C:\Data\settings.json' try { - Get-Item -Path $path -ErrorAction Stop + Get-Item -Path $filePath -ErrorAction 'Stop' } catch { $errorRecord = $_ # Capture immediately @@ -200,8 +340,8 @@ catch { ## Credential Handling 1. Use `[PSCredential]` for credential parameters, never `[string]` for passwords -1. Make credentials optional when the function can run without them -1. Use `[System.Management.Automation.Credential()]` attribute for flexibility +2. Make credentials optional when the function can run without them +3. Use `[System.Management.Automation.Credential()]` attribute for flexibility ```powershell function Connect-Service { @@ -231,20 +371,20 @@ function Connect-Service { ## Output 1. Write objects to pipeline immediately, don't batch into arrays -1. Use `Write-Verbose` for detailed operation information -1. Use `Write-Warning` for potential issues +2. Use `Write-Verbose` for detailed operation information +3. Use `Write-Warning` for potential issues ```powershell # Good - immediate output foreach ($item in $collection) { - $result = Process-Item $item + $result = Format-Item -InputObject $item $result # Output immediately } # Bad - batching $results = @() foreach ($item in $collection) { - $results += Process-Item $item + $results += Format-Item -InputObject $item } $results ``` @@ -289,8 +429,8 @@ function Get-UserData { ## Quotes 1. Use single quotes for string literals -1. Use double quotes only when variable expansion is needed -1. Quote hashtable keys only when necessary (hyphens, spaces) +2. Use double quotes only when variable expansion is needed +3. Quote hashtable keys only when necessary (hyphens, spaces) ```powershell # Good @@ -306,22 +446,124 @@ $title = 'Static string' ## Spacing 1. Spaces around all operators: `$x = 1 + 2` -1. Spaces around comparison operators: `$value -eq 10` -1. Space after commas and semicolons -1. No trailing spaces +2. Spaces around comparison operators: `$value -eq 10` +3. Space after commas and semicolons +4. No trailing spaces + +## Build Systems -## Semicolons +When a repository uses a build system (psake, Invoke-Build, etc.), use the build system's tasks for +operations like testing, building, publishing, and deployment rather than running commands directly +or creating separate scripts. Check for common build files: -1. Do not use semicolons as line terminators -1. Place each hashtable element on its own line +- `psakefile.ps1` or `psake.ps1` (psake) +- `*.build.ps1` (Invoke-Build) +- `build.ps1` (general build script) ```powershell -# Good -$options = @{ - Name = 'Value' - Size = 100 +# Good - use the build system +Invoke-psake -taskList Test +Invoke-Build -Task Test + +# Avoid - bypassing the build system +Invoke-Pester -Path .\tests\ +``` + +## Static Analysis + +PSScriptAnalyzer warnings indicate real issues. Fix the underlying problem rather than suppressing warnings. + +### Warnings to Always Fix + +These warnings represent naming and style violations that should be corrected: + +- **PSUseSingularNouns** - Rename function to use singular noun (`Get-Item` not `Get-Items`) +- **PSUseApprovedVerbs** - Use an approved verb from `Get-Verb` +- **PSAvoidUsingCmdletAliases** - Replace alias with full cmdlet name +- **PSAvoidUsingWriteHost** - Use `Write-Output`, `Write-Verbose`, or `Write-Information` + +```powershell +# Bad - suppressing instead of fixing +function Get-Items { # PSUseSingularNouns warning + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] + [CmdletBinding()] + param() + # Returns multiple items } -# Bad -$options = @{ Name = 'Value'; Size = 100 } +# Good - fix the naming +function Get-Item { + [CmdletBinding()] + param() + # Returns zero, one, or more items (singular noun is correct regardless) +} +``` + +### Suppression Requirements + +When suppression is genuinely necessary (rare), include a justification: + +1. Use `SuppressMessageAttribute` with the `Justification` parameter +2. Explain why the warning cannot be resolved +3. Reference external constraints if applicable + +```powershell +# Acceptable - justified suppression for API compatibility +function Get-AWSItems { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseSingularNouns', + '', + Justification = 'Matches AWS SDK naming convention for consistency with existing tooling' + )] + [CmdletBinding()] + param() +} +``` + +### Never Suppress Without Justification + +Suppressions without justification are not acceptable: + +```powershell +# Never do this +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] +``` + +## Pester + +### Skipping Tests + +`Set-ItResult -Skipped` (and `-Inconclusive`) ends the `It` block immediately - it throws an +internal error record that Pester catches and records as the test result. Code after the call +does not run, so a trailing `return` is unreachable dead code; do not add one. Reviewers, +including automated ones, recurrently suggest the redundant `return`. + +```powershell +# Good - Set-ItResult ends the test; nothing after it runs +It 'Validates the required version' { + if (-not $dependency.ContainsKey('RequiredVersion')) { + Set-ItResult -Skipped -Because 'No RequiredVersion to validate' + } + Test-VersionConstraint -Version $dependency.RequiredVersion | Should -BeTrue +} + +# Bad - the return can never execute; Set-ItResult already threw +It 'Validates the required version' { + if (-not $dependency.ContainsKey('RequiredVersion')) { + Set-ItResult -Skipped -Because 'No RequiredVersion to validate' + return + } + Test-VersionConstraint -Version $dependency.RequiredVersion | Should -BeTrue +} +``` + +Prefer `-Skip:$condition` on `It`, `Context`, or `Describe` when the condition is known at +discovery time; reserve `Set-ItResult -Skipped` for conditions only knowable at runtime inside +the test body. + +```powershell +# Good - a discovery-time condition uses the -Skip parameter +It 'Runs only on Windows' -Skip:(-not $IsWindows) { + Get-Service | Should -Not -BeNullOrEmpty +} ``` diff --git a/instructions/releases.instructions.md b/instructions/releases.instructions.md index 17db68a..17aa7c7 100644 --- a/instructions/releases.instructions.md +++ b/instructions/releases.instructions.md @@ -57,28 +57,29 @@ Follow [Semantic Versioning](https://semver.org/): ## Pre-Release Checklist -Before creating a release: +Follow `git-workflow.instructions.md` for branching and PR workflow. The steps below are +release-specific: 1. **Verify current release state**: Run `gh release list --limit 5` to check the most recent releases. Compare the latest released version against the version in CHANGELOG.md. If they match, the changelog version needs to be incremented. If the changelog is already ahead, use that version. NEVER release a version that already exists. -1. **Check repository-specific instructions**: Review `repository-specific.instructions.md` for +2. **Check repository-specific instructions**: Review `repository-specific.instructions.md` for any additional release requirements specific to this repository -1. **Update CHANGELOG.md**: Add new version section with all changes -1. **Update version numbers**: Bump version in relevant files as needed -1. **Update changelog links**: Add comparison link for the new version at the bottom of +3. **Update CHANGELOG.md**: Add new version section with all changes +4. **Update version numbers**: Bump version in relevant files as needed +5. **Update changelog links**: Add comparison link for the new version at the bottom of CHANGELOG.md (e.g., `[0.2.0]: https://github.com/owner/repo/compare/v0.1.0...v0.2.0`) -1. **Run tests**: Ensure all tests pass -1. **Commit changes**: Commit all version updates before creating the release -1. **Push to remote**: Push commits to the repository -1. **Create release**: Use the `gh release create` command with `--notes-file` +6. **Run tests**: Ensure all tests pass +7. **Commit changes**: Commit all version updates +8. **Create PR and wait for merge**: Follow the PR workflow in `git-workflow.instructions.md` +9. **Create release**: After PR is merged, use `gh release create` with `--notes-file` ## Post-Release After creating a release: 1. Verify the release appears correctly on GitHub -1. Check that release notes display properly (no formatting issues) -1. Confirm download links work if applicable -1. Notify team members if this is a significant release +2. Check that release notes display properly (no formatting issues) +3. Confirm download links work if applicable +4. Notify team members if this is a significant release diff --git a/instructions/shorthand.instructions.md b/instructions/shorthand.instructions.md index 77b09cf..de68961 100644 --- a/instructions/shorthand.instructions.md +++ b/instructions/shorthand.instructions.md @@ -37,6 +37,7 @@ use full, descriptive words instead of shorthand or abbreviations. | Err | Error | | Msg | Message | | Conn | Connection / Connections | +| Dir | Directory | | Cmd | Command | | Svc | Service | | Cfg | Configuration | diff --git a/instructions/testing.instructions.md b/instructions/testing.instructions.md index ce68dd4..4753984 100644 --- a/instructions/testing.instructions.md +++ b/instructions/testing.instructions.md @@ -7,6 +7,17 @@ description: 'Test writing best practices and conventions' Language-agnostic guidelines for writing effective tests. +## Discovering Existing Test Tooling + +Before creating scripts for test-related tasks (running tests, gathering coverage, generating reports): + +1. **Check for build systems** - Look for `Makefile`, `build.ps1`, `package.json` scripts, `tox.ini`, + `pyproject.toml`, or similar build configuration files +2. **Search README and CI configs** - Existing commands are often documented or visible in CI workflows +3. **Ask the user** - If unsure whether tooling exists, ask before creating anything new + +**Never create new scripts when existing build tooling already handles the task.** + ## Test Structure ### Arrange-Act-Assert (AAA) @@ -245,9 +256,9 @@ adminUser = createTestUser({ role: "admin" }) Prioritize testing: 1. Business-critical functionality -1. Error handling and edge cases -1. Security-sensitive code -1. Complex algorithms +2. Error handling and edge cases +3. Security-sensitive code +4. Complex algorithms ### Coverage Goals diff --git a/instructions/update.instructions.md b/instructions/update.instructions.md index 9760d58..4fc7231 100644 --- a/instructions/update.instructions.md +++ b/instructions/update.instructions.md @@ -29,6 +29,20 @@ Repositories control AIM behavior through `aim.config.json` in the repository ro "description": "Community-contributed instructions from GitHub" } ] + }, + "skills": { + "enabled": true, + "vendorPath": ".agents/skills", + "dependencies": [ + { + "name": "psake", + "source": "psake/psake-llm-tools", + "path": "plugins/psake/skills/psake", + "version": "v2.2.0", + "format": "skill-md", + "description": "psake build authoring (Agent Skill, agentskills.io)" + } + ] } } ``` @@ -40,6 +54,13 @@ Repositories control AIM behavior through `aim.config.json` in the repository ro - `modules.exclude` - List of modules to exclude (takes precedence over include) - `externalSources.enabled` - Enable fetching from external repositories - `externalSources.repositories` - List of external instruction sources +- `skills.enabled` - Enable vendoring declared Agent Skill (SKILL.md) dependencies into the repo +- `skills.vendorPath` - Directory skills are vendored into (default `.agents/skills`, the + cross-client Agent Skills convention) +- `skills.dependencies` - List of skills to vendor, each with `name`, `source` (repo), `path` + (skill folder within the source), `version` (tag to pin, or `latest`), `format` (`skill-md`), + and `description`. Unlike instruction modules, skills are copied to `vendorPath` (not + `instructions/`) and routed via `AGENTS.md` - see step 7 ## Update Procedure @@ -82,12 +103,12 @@ Based on `aim.config.json`: For each instruction file in the upstream `instruction-templates/` folder: 1. Check if the module should be synced based on configuration -1. Check if the file already exists in the downstream `instructions/` folder -1. **If the file exists, ask the user:** +2. Check if the file already exists in the downstream `instructions/` folder +3. **If the file exists, ask the user:** - "File X already exists. Overwrite with upstream version? (yes/no/diff)" - If "diff", show the differences between local and upstream versions - Only overwrite if the user confirms -1. **If the file is new**, copy it without prompting +4. **If the file is new**, copy it without prompting ### 6. Handle External Sources @@ -95,9 +116,9 @@ If `externalSources.enabled` is true and a needed language/framework instruction AIM: 1. Check each configured external repository in order -1. For awesome-copilot, look in the `instructions/` path for matching `.instructions.md` files -1. Download the instruction file and copy to the downstream `instructions/` folder -1. Inform the user which files were fetched from external sources +2. For awesome-copilot, look in the `instructions/` path for matching `.instructions.md` files +3. Download the instruction file and copy to the downstream `instructions/` folder +4. Inform the user which files were fetched from external sources **Example external fetch:** @@ -106,21 +127,50 @@ Fetching python.instructions.md from github/awesome-copilot... Fetching react.instructions.md from github/awesome-copilot... ``` -### 7. Update AGENTS.md +### 7. Handle Skill Dependencies + +If `skills.enabled` is true, vendor each declared Agent Skill (SKILL.md format) into the +repository so it travels with the code and any agent can use it - materialized like an instruction +module, not installed per-developer. Skills are NOT copied into `instructions/`; they are vendored +under `skills.vendorPath` (default `.agents/skills`), the cross-client +[Agent Skills](https://agentskills.io) convention that conforming agents discover directly. + +For each entry in `skills.dependencies`: + +1. Resolve `source` at the pinned `version` and locate the skill folder at `path` (the directory + containing `SKILL.md`). `version` is an exact tag or `latest`; `latest` means the most recent + release tag of `source` (its newest version tag when the source publishes no GitHub releases), + never the default branch's moving HEAD, so every agent vendors identical contents. +2. Copy that folder verbatim to `//` (the `SKILL.md` plus any `references/`, + `scripts/`, or `assets/`). Do not edit the vendored copy - re-sync from upstream instead. +3. **If `//` already exists, ask the user** before overwriting (same posture as + instruction files): overwrite / skip / diff. +4. Record or refresh upstream attribution and license in `/NOTICE.md`. +5. Route the skill in `AGENTS.md`: add a row to the Instruction Applicability Matrix mapping the + relevant task type to `//SKILL.md`, and list it in the "Skill Dependencies" + section. This is what makes any AGENTS-aware agent consult the skill. +6. Ensure a `CLAUDE.md` exists whose first line imports `AGENTS.md` (`@AGENTS.md`). Claude Code + reads `CLAUDE.md` - not `AGENTS.md` and not `/` - so this import is the bridge that + carries the routing into Claude Code. Preserve any Claude-specific content below the import. + +Agents that natively scan `.agents/skills/` (for example Cursor and opencode) pick the skill up +directly; the `AGENTS.md` routing plus the `CLAUDE.md` bridge covers agents that do not. + +### 8. Update AGENTS.md - Replace the HTML comment block at the top (the comment starting with ` diff --git a/aim.config.json b/aim.config.json index 74587c5..d6312e5 100644 --- a/aim.config.json +++ b/aim.config.json @@ -26,5 +26,27 @@ "description": "Community-contributed instructions from GitHub's awesome-copilot repository" } ] + }, + "skills": { + "enabled": true, + "vendorPath": ".agents/skills", + "dependencies": [ + { + "name": "psake", + "source": "psake/psake-llm-tools", + "path": "plugins/psake/skills/psake", + "version": "v2.2.0", + "format": "skill-md", + "description": "psake build authoring and patterns (Agent Skill, agentskills.io)" + }, + { + "name": "powershellbuild", + "source": "psake/psake-llm-tools", + "path": "plugins/powershellbuild/skills/powershellbuild", + "version": "v2.2.0", + "format": "skill-md", + "description": "PowerShell module build/test/publish via PowerShellBuild (Agent Skill)" + } + ] } } From 678bbee36a6b3f10a580ff96b9cf848040f37be0 Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Tue, 18 Aug 2026 21:14:33 -0400 Subject: [PATCH 3/5] chore(aim): pin the vendored skills license link to v2.2.0 The skills are pinned to a tag but the attribution linked LICENSE on main, which moves independently of the vendored copies. --- .agents/skills/NOTICE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/NOTICE.md b/.agents/skills/NOTICE.md index 474636a..c83b55e 100644 --- a/.agents/skills/NOTICE.md +++ b/.agents/skills/NOTICE.md @@ -5,7 +5,7 @@ redistributed under their original license. - Source: - Version: v2.2.0 -- License: MIT (see ) +- License: MIT (see ) - Skills: - `psake` — from `plugins/psake/skills/psake` - `powershellbuild` — from `plugins/powershellbuild/skills/powershellbuild` From b1f3de859340f582b25ddf6d175d486ca7e9658f Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Tue, 18 Aug 2026 21:28:40 -0400 Subject: [PATCH 4/5] chore(review): stop reviewing content copied from upstream Findings against vendored skills or synced instruction modules cannot be fixed here, and both upstreams are reviewed where they live. One sync PR drew 115 inline comments; 109 were against copied content. --- .coderabbit.yaml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000..2511746 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,39 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +# +# Keep review attention on this repository's own code. +# +# Two directories here hold content that is copied in from elsewhere, and a +# finding against either of them cannot be fixed here -- the fix has to land +# upstream and arrive on the next sync. Reviewing them downstream produces +# comments nobody can action, multiplied by every repository in the fleet: one +# AIM sync generated 115 inline comments, of which 109 were against copied +# content and 6 against anything this repository actually owns. +# +# Only exclusions are listed. Adding an inclusion pattern would turn this into +# an allowlist and silently stop everything else from being reviewed. +reviews: + path_filters: + # Agent Skills vendored verbatim from psake/psake-llm-tools, pinned in + # aim.config.json. .agents/skills/NOTICE.md and step 7.2 of + # instructions/update.instructions.md both say never to edit these in place + # -- re-sync from upstream instead -- so a review comment here is an + # instruction to do the one thing that is not allowed. Their own repository + # maintains them. + - "!.agents/skills/**" + + # Instruction modules synced from tablackburn/ai-agent-instruction-modules. + # That repository has CodeRabbit installed and reviews every human PR, so + # this content is already reviewed where it lives and where it can be + # changed. Listed file by file on purpose: repository-specific.instructions.md + # is NEVER copied from upstream, is genuinely local, and stays reviewed. + - "!instructions/agent-workflow.instructions.md" + - "!instructions/contributing.instructions.md" + - "!instructions/git-workflow.instructions.md" + - "!instructions/github-cli.instructions.md" + - "!instructions/markdown.instructions.md" + - "!instructions/powershell.instructions.md" + - "!instructions/readme.instructions.md" + - "!instructions/releases.instructions.md" + - "!instructions/shorthand.instructions.md" + - "!instructions/testing.instructions.md" + - "!instructions/update.instructions.md" From 3617f5b921f3b51bc7e9ed6f9e287b039b3c5bc2 Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Tue, 18 Aug 2026 21:41:54 -0400 Subject: [PATCH 5/5] chore(review): keep the skills NOTICE under review Exclude the two vendored skill folders rather than all of .agents/skills. NOTICE.md is attribution we write, and reviewing it caught the license link pointing at a moving branch. --- .coderabbit.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 2511746..06c5858 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -19,7 +19,12 @@ reviews: # -- re-sync from upstream instead -- so a review comment here is an # instruction to do the one thing that is not allowed. Their own repository # maintains them. - - "!.agents/skills/**" + # + # The skill folders only. .agents/skills/NOTICE.md is ours: we write the + # attribution, and a review of it caught the license link still pointing at + # a moving branch while the skills were pinned to a tag. + - "!.agents/skills/psake/**" + - "!.agents/skills/powershellbuild/**" # Instruction modules synced from tablackburn/ai-agent-instruction-modules. # That repository has CodeRabbit installed and reviews every human PR, so