agentsclimarketplace

Psake

Skill psake/psake-llm-tools/plugins/psake/skills/psake

Skills, instructions, and other types of files that may help with LLM usage.

Install
npx -y skills add psake/psake-llm-tools --skill psake

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

This skill should be used when the user asks to "create a psakefile", "set up a psake build", "add psake caching", "migrate to psake v5", "troubleshoot a psake build", or mentions psake, psakefile.ps1, Invoke-psake, build task dependencies, exec blocks, PsakeBuildResult, Get-PsakeBuildPlan, or PowerShell build automation for .NET, Node.js, or Docker projects. Also triggers on requests to set up CI/CD pipelines (GitHub Actions, Azure Pipelines, GitLab CI) using psake.

SKILL.md

13.6 KB, as published. Nobody here has run it

psake Build Automation

psake is a PowerShell build automation tool using a DSL for task-based builds with dependencies. psake v5 introduces a two-phase compile/run model, declarative syntax, file-based caching, and structured output.

Decision Tree

What kind of build are you creating?

  1. PowerShell module → Use PowerShellBuild module (see references/powershell-modules.md)
  2. .NET/Node.js/Docker → See references/build-types.md
  3. Simple custom build → Continue below for core psake patterns

Build complexity?

  • Simple (< 5 tasks, single project) → Use patterns in this file
  • Complex (CI/CD, multiple environments, dynamic tasks) → See references/advanced.md

Quick Start

# Install
Install-Module -Name psake -Scope CurrentUser -Force

# Run — interactive (prints formatted output to console)
Invoke-psake                              # Run 'Default' task
Invoke-psake -taskList Build, Test        # Run specific tasks
Invoke-psake -docs                        # Show task documentation

# Run — programmatic: LLM agents, CI scripts, build.ps1 wrappers
# -Quiet suppresses all console output and returns a PsakeBuildResult object.
# Always use this form when you need to check success or read task results.
$result = Invoke-psake -taskList Build, Test -Quiet
$result.Success        # $true / $false — check this, don't parse console text
$result.ErrorMessage   # populated when Success is $false
$result.Tasks          # PsakeTaskResult[] — Name, Status, Duration, Cached

Minimal psakefile.ps1

Version 5

Properties {
    $BuildDir = Join-Path $PSScriptRoot 'build'
}

Task Default -depends Build

Task Clean {
    if (Test-Path $BuildDir) { Remove-Item $BuildDir -Recurse -Force }
    New-Item -ItemType Directory -Path $BuildDir -Force | Out-Null
}

Task Build -depends Clean {
    exec { dotnet build -o $BuildDir }
}

Task Test -depends Build {
    exec { dotnet test }
}

Programmatic Invocation

Always use -Quiet when invoking psake from a script, CI step, or LLM agent. Without it, psake streams formatted text to the console — noisy and unparseable. With it, psake returns a PsakeBuildResult object and produces no console output.

$result = Invoke-psake -buildFile ./psakefile.ps1 -taskList Build, Test -Quiet

if (-not $result.Success) {
    Write-Error $result.ErrorMessage
    exit 1
}

# Inspect task-level results
$result.Tasks | ForEach-Object {
    "$($_.Name): $($_.Status) ($($_.Duration.TotalSeconds)s)"
}

build.ps1 Entry-Point Template

Projects often have a thin build.ps1 wrapper that bootstraps dependencies and delegates to psake. Generate it with the -Quiet pattern so any caller — human or LLM — gets structured results:

# build.ps1
#
# Usage (interactive):   ./build.ps1                 # default task
#                        ./build.ps1 Build, Test     # specific tasks
#                        ./build.ps1 -Bootstrap      # install deps first
#
# Usage (programmatic):  Invoke-psake -buildFile ./psakefile.ps1 -Quiet
#   -Quiet returns a PsakeBuildResult (.Success, .Tasks, .ErrorMessage).
#   Use that form directly in CI steps and LLM agents — skip this script.

[CmdletBinding()]
param(
    [ArgumentCompleter({
        param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
        try {
            Get-PSakeScriptTasks -BuildFile (Join-Path $PSScriptRoot 'psakefile.ps1') -ErrorAction Stop |
                Where-Object { $_.Name -like "$WordToComplete*" } |
                Select-Object -ExpandProperty Name
        } catch { @() }
    })]
    [string[]]$Task = 'Default',

    [switch]$Bootstrap
)

$ErrorActionPreference = 'Stop'

if ($Bootstrap) {
    if (-not (Get-Module -ListAvailable -Name PSDepend)) {
        Install-Module -Name PSDepend -Scope CurrentUser -Force -AllowClobber
    }
    $psDependArgs = @{
        Path          = $PSScriptRoot
        Recurse       = $false
        Install       = $true
        Import        = $true
        Force         = $true
    }
    Invoke-PSDepend @psDependArgs
} else {
    # Try importing cached modules first — avoids file-lock contention when CI
    # jobs share a module cache and one job is mid-install.
    $psDependArgs = @{
        Path          = $PSScriptRoot
        Recurse       = $false
        Import        = $true
        Force         = $true
        WarningAction = 'SilentlyContinue'
    }
    $imported = $false
    try { Invoke-PSDepend @psDependArgs; $imported = $true } catch {}

    if (-not $imported) {
        $psDependArgs['Install'] = $true
        try {
            Invoke-PSDepend @psDependArgs
        } catch {
            throw "Dependency install failed. If modules are locked, restart the build environment or re-run with -Bootstrap."
        }
    }
}

$psakeArgs = @{
    buildFile = Join-Path $PSScriptRoot 'psakefile.ps1'
    taskList  = $Task
    Quiet     = $true
}
$result = Invoke-psake @psakeArgs

if (-not $result.Success) {
    Write-Error $result.ErrorMessage
    exit 1
}

For LLM agents: skip build.ps1 entirely. Call Invoke-psake -Quiet directly and inspect the returned PsakeBuildResult — you get structured data without spawning a child process or parsing output.

Core Commands

Task

Two equivalent syntaxes — use whichever reads better for your build:

# Classic syntax (works in v4 and v5)
Task Build -depends Clean -description "Compile project" {
    exec { dotnet build }
}

# Declarative syntax (v5 — hashtable with validated keys)
Task 'Build' @{
    DependsOn   = 'Clean'
    Description = 'Compile project'
    Action      = { exec { dotnet build } }
}

The declarative syntax validates keys at parse time — typos like DependOn throw immediately. Valid keys: Action, DependsOn, Inputs, Outputs, PreAction, PostAction, PreCondition, PostCondition, ContinueOnError, Description, Alias, RequiredVariables.

Task with Caching

Tasks with Inputs and Outputs are content-addressed cached in .psake/cache/. If input file hashes haven't changed and output files exist, the task is skipped.

Task 'Build' @{
    DependsOn = 'Clean'
    Inputs    = 'src/**/*.cs', 'src/**/*.csproj'
    Outputs   = 'bin/**/*.dll'
    Action    = { exec { dotnet build -c $Configuration } }
}

Inputs/Outputs also accept scriptblocks for dynamic file resolution:

Task 'Build' @{
    Inputs  = { Get-ChildItem src -Recurse -Include *.cs }
    Outputs = { Get-ChildItem bin -Recurse -Include *.dll -ErrorAction SilentlyContinue }
    Action  = { exec { dotnet build } }
}

Use Clear-PsakeCache to force a full rebuild, or Invoke-psake -NoCache for a single run.

Conditional Execution

Task Deploy -precondition { $env:CI -eq 'true' } -description "Deploy to prod" {
    exec { ./deploy.ps1 }
}

Properties

Variables available to all tasks. Can be overridden via -properties parameter.

# Scriptblock syntax
Properties {
    $Configuration = 'Release'
    $Version = '1.0.0'
}

# Hashtable syntax (v5)
Properties @{
    Configuration = 'Release'
    Version       = '1.0.0'
}

Override: Invoke-psake -properties @{ Configuration = 'Debug' }

Version

Pin your build script to a psake major version. The compile phase rejects version mismatches.

Version 5

exec

Runs external commands, fails build on non-zero exit:

exec { dotnet build }                                    # Basic
exec { npm install } "npm install failed"                # Custom error
exec { nuget restore } -maxRetries 3                     # Retry flaky ops
exec { npm test } -workingDirectory './frontend'         # Different directory
exec { ./slow-build.ps1 } -TimeoutSeconds 600            # Timeout (v5)

Assert

Assert (Test-Path $SrcDir) "Source directory not found"
Assert (-not [string]::IsNullOrEmpty($ApiKey)) "API key required"

Include

Include "./shared/common-tasks.ps1"

FormatTaskName

FormatTaskName "▶ {0}"
# Or with scriptblock:
FormatTaskName { param($taskName) Write-Host "[$taskName]" -ForegroundColor Cyan }

TaskSetup / TaskTearDown

TaskSetup { Write-Host "Starting: $($psake.context.currentTaskName)" }
TaskTearDown { Write-Host "Finished: $($psake.context.currentTaskName)" }

Structured Output

Invoke-psake returns a PsakeBuildResult object:

$result = Invoke-psake -Quiet
$result.Success          # $true / $false
$result.Duration         # TimeSpan
$result.Tasks            # PsakeTaskResult[] with Name, Status, Duration, Cached
$result.ErrorMessage     # Error details if failed

The $psake.build_success variable is still set after each build for backward compatibility.

For CI pipelines, use JSON output:

Invoke-psake -OutputFormat JSON

Invoke-psake Parameters

ParameterDescription
-buildFilePath to build script (default: psakefile.ps1)
-taskListTasks to execute (default: 'Default')
-parametersHashtable passed to build script (set before Properties)
-propertiesHashtable to override Properties block (set after Properties)
-docsDisplay task documentation
-nologoSuppress banner
-OutputFormatDefault, JSON, or GitHubActions (v5)
-NoCacheBypass task caching for this run (v5)
-CompileOnlyReturn build plan without executing (v5)
-QuietSuppress console output; still returns PsakeBuildResult (v5)

Testability APIs

Inspect the Build Plan

$plan = Get-PsakeBuildPlan -BuildFile './psakefile.ps1'
$plan.ExecutionOrder    # ['Clean', 'Build', 'Test', 'Default']
$plan.TaskMap['build'].DependsOn  # ['Clean']
$plan.IsValid           # $true
$plan.ValidationErrors  # @()

The plan can also be piped into Invoke-psake:

Get-PsakeBuildPlan | Invoke-psake

Test a Task in Isolation

$result = Test-PsakeTask -BuildFile './psakefile.ps1' -TaskName 'Build' -Variables @{
    Configuration = 'Debug'
}
$result.Status    # 'Executed'
$result.Duration  # TimeSpan

Common Patterns

Environment-Specific

Properties {
    $Env = if ($env:ENVIRONMENT) { $env:ENVIRONMENT } else { 'Development' }
}

Task Deploy {
    switch ($Env) {
        'Production' { exec { ./deploy-prod.ps1 } }
        default      { Write-Host "Skipping deploy for $Env" }
    }
}

Multi-Project

Task BuildAll -depends BuildBackend, BuildFrontend

Task BuildBackend {
    Push-Location ./backend
    try { exec { dotnet build } }
    finally { Pop-Location }
}

Task BuildFrontend {
    Push-Location ./frontend
    try { exec { npm run build } }
    finally { Pop-Location }
}

Variable Scoping Between Tasks

Tasks don't share local variables. Use $script: scope to pass data between dependent tasks:

Task GetFiles {
    $script:Files = Get-ChildItem -Path $SrcDir -Filter *.ps1
}

Task ProcessFiles -depends GetFiles {
    foreach ($file in $script:Files) {
        # Process each file
    }
}

Note: psake tasks don't have return values. $script: scoped variables are the recommended approach for task-to-task data sharing.

Validating a psakefile

Using Get-PsakeBuildPlan (recommended)

The compile phase catches circular dependencies, missing tasks, and version mismatches before any task runs:

$plan = Get-PsakeBuildPlan -BuildFile './psakefile.ps1'
if (-not $plan.IsValid) {
    $plan.ValidationErrors | ForEach-Object { Write-Error $_ }
} else {
    Write-Host "✓ Build plan valid — execution order: $($plan.ExecutionOrder -join ' → ')"
}

Syntax Check

$errors = $null
$null = [System.Management.Automation.Language.Parser]::ParseFile(
    (Resolve-Path 'psakefile.ps1'), [ref]$null, [ref]$errors
)
if ($errors) { $errors | ForEach-Object { Write-Error $_.ToString() } }
else { Write-Host "✓ Syntax valid" -ForegroundColor Green }

Troubleshooting

ProblemSolution
Build fails but CI shows successUse exec { } for all external commands
Cross-platform path issuesUse Join-Path instead of \ or /
Module not found in CIInstall-Module -Name psake -Scope CurrentUser -Force
Properties not overridingUse -properties (not -parameters) to override Properties block
Variable undefined in dependent taskUse $script:VarName to share data between tasks
Circular dependency errorCheck Get-PsakeBuildPlan output for ValidationErrors
Task skipped unexpectedlyMay be cached — run with -NoCache or Clear-PsakeCache
default.ps1 not foundv5 removed default.ps1 fallback — rename to psakefile.ps1

References

  • references/upgrading-to-v5.md - Migration guide, caching for faster builds, structured output, testability APIs
  • references/powershell-modules.md - PowerShellBuild module for PS module development
  • references/build-types.md - .NET, Node.js, Docker build patterns
  • references/advanced.md - Dynamic tasks, CI/CD integration, $psake reference

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.