<#
.SYNOPSIS
Install the amont-agent binary on Windows. Nothing else.
.DESCRIPTION
irm https://raw.githubusercontent.com/fredericrous/amont-agent/main/install/install.ps1 | iex
The counterpart to install/install.sh, which is POSIX sh and therefore
reaches Windows only through Git Bash. This one runs in the PowerShell
that ships with Windows, so `curl | sh` stops being the only documented
path on a platform the hooks genuinely support and CI genuinely tests.
Like its sibling it deliberately turns NOTHING on. It downloads a verified
binary, puts it where the shims already look, and says what to run next.
An installer that enabled hooks — or set init.templateDir so every future
clone got them — would contradict the project's central promise on first
contact with the machine.
.PARAMETER Version
A specific release, e.g. "v1.0.0". Defaults to the latest.
.PARAMETER BinDir
Where to put the executable. Defaults to $HOME\.local\bin.
`amont-agent install` writes this binary's ABSOLUTE path into
settings.json, so the directory decides only whether you can type the
command yourself — Claude Code finds it either way.
#>
[CmdletBinding()]
param(
[string]$Version = $env:AMONT_AGENT_VERSION,
[string]$BinDir = $env:AMONT_AGENT_BIN_DIR
)
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version Latest
$Repo = 'fredericrous/amont-agent'
if (-not $BinDir) { $BinDir = Join-Path $HOME '.local\bin' }
if (-not $Version) { $Version = 'latest' }
function Write-Ok ($m) { Write-Host " [ok] $m" -ForegroundColor Green }
function Write-Warn ($m) { Write-Host " [!] $m" -ForegroundColor Yellow }
function Fail ($m) { Write-Host " [x] $m" -ForegroundColor Red; exit 1 }
# Windows PowerShell 5.1 still negotiates TLS 1.0 by default, which GitHub
# refuses outright — the download fails with a connection error that says
# nothing about the cause. PowerShell 7 already defaults to TLS 1.2+.
try {
[Net.ServicePointManager]::SecurityProtocol =
[Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
} catch {
# Not fatal: PS7 has no mutable ServicePointManager and does not need one.
}
Write-Host ''
Write-Host ' amont-agent installer'
Write-Host ''
# Only x86_64 is published today. Windows on ARM runs x64 binaries through
# emulation, so this is a working install rather than a refusal — said out
# loud, because a silently emulated binary is a surprise worth naming.
$arch = $env:PROCESSOR_ARCHITECTURE
$target = 'x86_64-pc-windows-msvc'
if ($arch -eq 'ARM64') {
Write-Warn 'ARM64 detected — installing the x64 build, which Windows runs under emulation.'
}
if ($Version -eq 'latest') {
try {
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest" `
-Headers @{ 'User-Agent' = 'amont-agent-installer' }
$Version = $release.tag_name
} catch {
Fail "could not determine the latest release (rate limited? pass -Version v1.2.3): $_"
}
}
$v = $Version -replace '^v', ''
$name = "amont-agent-$v-$target"
$base = "https://github.com/$Repo/releases/download/v$v"
Write-Host " version: $v"
Write-Host " platform: $target"
Write-Host " into: $BinDir"
Write-Host ''
$tmp = Join-Path ([System.IO.Path]::GetTempPath()) ("amont-agent-" + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $tmp -Force | Out-Null
try {
$zip = Join-Path $tmp "$name.zip"
Write-Host ' downloading...'
try {
Invoke-WebRequest -Uri "$base/$name.zip" -OutFile $zip -UseBasicParsing
} catch {
Fail "download failed: $base/$name.zip"
}
# Checksums are not optional here. This binary runs on every commit with
# your credentials and reads every staged file; verifying what it is
# before putting it in that position is the argument the project makes
# about its own dependencies, applied to itself.
$sums = Join-Path $tmp 'SHA256SUMS'
try {
Invoke-WebRequest -Uri "$base/SHA256SUMS" -OutFile $sums -UseBasicParsing
} catch {
$sums = $null
Write-Warn 'no SHA256SUMS published for this release - the download was NOT verified'
}
if ($sums) {
$got = (Get-FileHash -Path $zip -Algorithm SHA256).Hash.ToLower()
$line = Select-String -Path $sums -Pattern ([regex]::Escape("$name.zip")) |
Select-Object -First 1
if (-not $line) { Fail "SHA256SUMS has no entry for $name.zip" }
$want = ($line.Line -split '\s+')[0].ToLower()
if ($got -ne $want) {
Fail "checksum mismatch - refusing to install`n expected $want`n got $got"
}
Write-Ok 'checksum verified'
}
Expand-Archive -Path $zip -DestinationPath $tmp -Force
$src = Join-Path $tmp $name
# Whether this is an upgrade decides what to say at the end: the
# first-install steps are wrong advice the second time.
$upgrading = Test-Path (Join-Path $BinDir 'amont-agent.exe')
New-Item -ItemType Directory -Path $BinDir -Force | Out-Null
foreach ($exe in @('amont-agent.exe')) {
$from = Join-Path $src $exe
if (Test-Path $from) {
$to = Join-Path $BinDir $exe
# Copy beside the destination and move it into place: replacing a
# RUNNING executable in place fails on Windows with a sharing
# violation, and a move is atomic, so a half-copied amont-agent.exe
# never exists.
$staged = "$to.new"
Copy-Item -Path $from -Destination $staged -Force
Move-Item -Path $staged -Destination $to -Force
Write-Ok "installed $to"
}
}
} finally {
Remove-Item -Path $tmp -Recurse -Force -ErrorAction SilentlyContinue
}
Write-Host ''
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
if ($userPath -notlike "*$BinDir*") {
Write-Warn "$BinDir is not on your PATH."
Write-Host ' The shims find the binary there regardless; this is so YOU can run it:'
Write-Host ''
Write-Host " [Environment]::SetEnvironmentVariable('Path', `"`$env:Path;$BinDir`", 'User')"
Write-Host ''
}
if ($upgrading) {
Write-Host ' Upgraded. The settings.json entry points at this path, so'
Write-Host ' nothing needs rewiring. Confirm it still fires:'
Write-Host ''
Write-Host ' amont-agent doctor'
Write-Host ''
} else {
Write-Host ' Installed, and wired into nothing. The guard does not run until'
Write-Host ' Claude Code is told about it:'
Write-Host ''
Write-Host ' amont-agent install # print the settings block, write nothing'
Write-Host ' amont-agent install --write # merge it into the Claude settings.json'
Write-Host ' amont-agent doctor # installed, runnable, and actually firing?'
Write-Host ''
Write-Host ' Every rule but pipe-to-tail ships as observe, so nothing is refused'
Write-Host ' until you have seen what it would have caught:'
Write-Host ''
Write-Host ' amont-agent status'
Write-Host ''
}