logancyang_obsidian-copilot/docs/install-codex-agent-mode-windows.ps1
Logan Yang ab96aebcd8
docs: Windows setup guide for Claude and Codex Agent Mode (#2542)
* docs: add Windows setup guide for Claude Code Agent Mode

Windows users hit a confusing dead end: the Claude Code installer does not
add the binary to PATH, so `claude` and `where.exe claude` report
not-found even on a healthy install, leading users to think it broke. Copilot
resolves the binary by file path, not PATH, so the install is fine.

Add docs/agent-mode-windows-setup.md walking through install, sign-in,
Auto-detect / manual path, and troubleshooting, with the PATH gotcha called
out up front. Link it from docs/index.md and docs/agent-mode-and-tools.md.

Docs-only slice of logancyang/obsidian-copilot-preview#108; the in-plugin
not-found copy linking to this page is a follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: don't link v4 Windows guide from the v3 agent doc

agent-mode-and-tools.md documents the v3 in-process autonomous agent (vault
tools, @vault, max-iterations), a different feature from v4 Agent Mode (the
Claude Code / Codex / OpenCode coding-agent backends). The Windows guide is
about v4, so the callout there was misplaced. Keep only the standalone
docs/index.md entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: trim Windows guide to the exact command sequence

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: add Codex Windows installer for Agent Mode

* docs: script Claude Windows Agent Mode setup

* docs: harden Codex CLI path resolution

* docs: verify Codex login before finishing setup

* docs: avoid redundant Codex login prompts

* fix: auto-detect Codex ACP on Windows

* fix: address Windows agent setup review

* fix: align Claude Windows configure modal

* fix: clarify Windows PowerShell install label

* fix: use gist Windows install helpers

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 20:53:56 -07:00

175 lines
5.4 KiB
PowerShell

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
function Write-Step {
param([string]$Message)
Write-Host ""
Write-Host "==> $Message"
}
function Add-PathEntryForThisSession {
param([string]$PathEntry)
$needle = $PathEntry.TrimEnd("\")
foreach ($segment in $env:Path.Split(";", [System.StringSplitOptions]::RemoveEmptyEntries)) {
if ($segment.TrimEnd("\") -ieq $needle) {
return
}
}
$env:Path = "$PathEntry;$env:Path"
}
function Find-CodexCommand {
$candidatePaths = @()
if (-not [string]::IsNullOrWhiteSpace($env:CODEX_INSTALL_DIR)) {
$candidatePaths += (Join-Path $env:CODEX_INSTALL_DIR "codex.exe")
}
$candidatePaths += (Join-Path $env:LOCALAPPDATA "Programs\OpenAI\Codex\bin\codex.exe")
$candidatePaths += (Join-Path $env:LOCALAPPDATA "OpenAI\Codex\bin\codex.exe")
$localOpenAIBin = Join-Path $env:LOCALAPPDATA "OpenAI\Codex\bin"
if (Test-Path -LiteralPath $localOpenAIBin -PathType Container) {
$candidatePaths += Get-ChildItem -LiteralPath $localOpenAIBin -Directory -ErrorAction SilentlyContinue |
ForEach-Object { Join-Path $_.FullName "codex.exe" }
}
$pathCommand = Get-Command "codex" -ErrorAction SilentlyContinue
if ($null -ne $pathCommand -and -not [string]::IsNullOrWhiteSpace($pathCommand.Source)) {
$candidatePaths += $pathCommand.Source
}
$seen = @{}
$checked = @()
foreach ($candidate in $candidatePaths) {
if ([string]::IsNullOrWhiteSpace($candidate)) {
continue
}
$key = $candidate.ToLowerInvariant()
if ($seen.ContainsKey($key)) {
continue
}
$seen[$key] = $true
$checked += $candidate
if (Test-Path -LiteralPath $candidate -PathType Leaf) {
try {
& $candidate --version *> $null
if ($LASTEXITCODE -eq 0) {
return [PSCustomObject]@{
Bin = Split-Path -Parent $candidate
Path = $candidate
}
}
} catch {
continue
}
}
}
throw "A runnable codex.exe was not found. Checked: $($checked -join '; ')"
}
function Test-CodexLoggedIn {
param([string]$CodexCommand)
$previousErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = "Continue"
try {
$status = & $CodexCommand login status 2>&1
return ($LASTEXITCODE -eq 0 -and (($status -join "`n") -match "Logged in"))
} catch {
return $false
} finally {
$ErrorActionPreference = $previousErrorActionPreference
}
}
function Wait-CodexLogin {
param(
[string]$CodexCommand,
[int]$TimeoutSeconds = 600
)
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
while ((Get-Date) -lt $deadline) {
if (Test-CodexLoggedIn -CodexCommand $CodexCommand) {
return
}
Start-Sleep -Seconds 2
}
throw "Codex login was not completed within $TimeoutSeconds seconds. Run this script again after signing in."
}
Write-Step "Installing Codex CLI"
$previousNonInteractive = $env:CODEX_NON_INTERACTIVE
$env:CODEX_NON_INTERACTIVE = "1"
try {
Invoke-RestMethod "https://github.com/openai/codex/releases/latest/download/install.ps1" | Invoke-Expression
} finally {
if ([string]::IsNullOrWhiteSpace($previousNonInteractive)) {
Remove-Item Env:\CODEX_NON_INTERACTIVE -ErrorAction SilentlyContinue
} else {
$env:CODEX_NON_INTERACTIVE = $previousNonInteractive
}
}
$resolvedCodex = Find-CodexCommand
$codexBin = $resolvedCodex.Bin
$codex = $resolvedCodex.Path
Add-PathEntryForThisSession -PathEntry $codexBin
Write-Step "Signing in to Codex"
if (Test-CodexLoggedIn -CodexCommand $codex) {
Write-Host "Codex is already signed in."
} else {
Write-Host "Follow the Codex login prompts. This script will continue after login finishes."
& $codex login
Wait-CodexLogin -CodexCommand $codex
}
Write-Step "Installing codex-acp"
$arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq "Arm64") {
"aarch64"
} else {
"x86_64"
}
$acpDir = Join-Path $env:LOCALAPPDATA "Programs\codex-acp"
$zip = Join-Path $env:TEMP "codex-acp.zip"
$release = Invoke-RestMethod "https://api.github.com/repos/zed-industries/codex-acp/releases/latest"
$asset = $release.assets |
Where-Object { $_.name -like "codex-acp-*-$arch-pc-windows-msvc.zip" } |
Select-Object -First 1
if ($null -eq $asset) {
throw "No codex-acp Windows release was found for $arch."
}
New-Item -ItemType Directory -Force -Path $acpDir | Out-Null
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zip
Expand-Archive -Path $zip -DestinationPath $acpDir -Force
$acp = Join-Path $acpDir "codex-acp.exe"
if (-not (Test-Path -LiteralPath $acp -PathType Leaf)) {
throw "codex-acp.exe was not found at $acp"
}
try {
Set-Clipboard -Value $acp
$clipboardMessage = "The codex-acp.exe path has been copied to your clipboard."
} catch {
$clipboardMessage = "Copy this codex-acp.exe path:"
}
Write-Host ""
Write-Host "Done. $clipboardMessage"
Write-Host $acp
Write-Host ""
Write-Host "Next: Obsidian -> Settings -> Copilot -> Agents -> Codex -> Configure"
Write-Host "Paste this path into the binary path field, leave Environment variables empty, then save."