davidbond.net
Friday, 16 January 2026
Wednesday, 17 December 2025
Detecting AI Agent Terminals in PowerShell
Detecting AI Agent Terminals in PowerShell
Introduction
If you’re working with Visual Studio 2026, VS Code with Copilot, or other AI-assisted development tools, you may have noticed that these tools spawn terminal sessions for executing commands. I’ve created a PowerShell profile configuration that automatically detects these AI agent terminals and adjusts the experience accordingly.
Why This Matters
When an AI agent (like GitHub Copilot) runs commands in a terminal, you typically don’t need the full interactive experience - Oh My Posh themes, PSReadLine predictions, and fancy prompts just add overhead. Conversely, when you’re using the terminal, you want the full experience.
This profile script:
- Detects AI agent terminals (VS Code Copilot, Visual Studio 2026 DevHub)
- Displays a clear visual banner showing whether you or an AI is in control
- Optimizes the environment based on the terminal type
- Supports Nerd Fonts with ASCII fallbacks
The Setup
Step 1: Locate Your Profile
Open PowerShell and run:
$PROFILE
This shows the path to your profile script (typically ~\Documents\PowerShell\Microsoft.PowerShell_profile.ps1).
Step 2: Create or Edit Your Profile
If the file doesn’t exist:
New-Item -Path $PROFILE -ItemType File -Force
notepad $PROFILE
Step 3: Add the Configuration
Here’s the complete script broken down by section:
Mode Detection
# Detect Copilot/AI agent terminals
$script:parentProcessName = try { (Get-Process -Id $PID).Parent.Name } catch { $null }
$script:isCopilot = ($env:VSC_COPILOT_TERMINAL -eq "1") -or
($env:VS_TERMINAL_AGENT -eq "1") -or
($script:parentProcessName -eq "DevHub")
# Detect non-interactive/background terminals
$isNonInteractive = ($env:VSCODE_RESOLVING_TERMINAL -eq "1") -or
(-not [Environment]::UserInteractive)
This checks for:
VSC_COPILOT_TERMINAL- Set by VS Code for Copilot terminalsVS_TERMINAL_AGENT- Set by Visual Studio for agent terminalsDevHubparent process - Visual Studio 2026’s Copilot service
Visual Banner
The script displays a header banner showing who’s in control:
- Blue “COPILOT AGENT” banner when an AI is running commands
- Purple username banner for interactive sessions
if ($hasValidWindow) {
$width = $Host.UI.RawUI.WindowSize.Width
$time = Get-Date -Format "HH:mm:ss"
$user = $env:USERNAME.ToUpper()
if ($supportsNerdFonts) {
$copilotIcon = [char]::ConvertFromUtf32(0xF166A) # nf-md-robot
$userIcon = [char]::ConvertFromUtf32(0xF489) # nf-oct-terminal
$clockIcon = [char]::ConvertFromUtf32(0xF1425) # nf-md-clock_outline
} else {
$copilotIcon = "[BOT]"
$userIcon = ">"
$clockIcon = "@"
}
if ($script:isCopilot) {
$leftLabel = " $copilotIcon COPILOT AGENT "
$modeColor = "38;5;39" # Blue
} else {
$leftLabel = " $userIcon $user "
$modeColor = "38;5;99" # Purple
}
$rightLabel = " $time $clockIcon "
$fillCount = $width - $leftLabel.Length - $rightLabel.Length
$fillLine = if ($fillCount -gt 0) { [string]::new([char]0x2501, $fillCount) } else { "" }
Write-Host ""
Write-Host "`e[1;$($modeColor)m$leftLabel`e[0m`e[38;5;236m$fillLine`e[0m`e[90m$rightLabel`e[0m"
Write-Host ""
}
If you have Nerd Fonts installed (Windows Terminal, VS Code), you’ll see nice icons; otherwise, ASCII fallbacks are used.
Conditional Setup
if ($script:isCopilot) {
# Minimal prompt for AI agents
function global:prompt {
$Host.UI.RawUI.WindowTitle = "VS 2026 | Copilot"
"PS $($PWD.Path)> "
}
} else {
# Full Oh My Posh experience for humans
if (Get-Command oh-my-posh -ErrorAction SilentlyContinue) {
$poshTheme = "$env:POSH_THEMES_PATH\marcduiker.omp.json"
if (Test-Path $poshTheme) {
oh-my-posh init pwsh --config $poshTheme | Invoke-Expression
}
}
}
The Complete Script
Here’s the full profile script you can copy:
# ============================================================================
# PowerShell Profile - AI Agent Detection
# ============================================================================
# ----------------------------------------------------------------------------
# 1. MODE DETECTION
# ----------------------------------------------------------------------------
$script:parentProcessName = try { (Get-Process -Id $PID).Parent.Name } catch { $null }
$script:isCopilot = ($env:VSC_COPILOT_TERMINAL -eq "1") -or
($env:VS_TERMINAL_AGENT -eq "1") -or
($script:parentProcessName -eq "DevHub")
$isNonInteractive = ($env:VSCODE_RESOLVING_TERMINAL -eq "1") -or
(-not [Environment]::UserInteractive)
$hasValidWindow = try { $Host.UI.RawUI.WindowSize.Width -gt 0 } catch { $false }
$supportsNerdFonts = ($env:WT_SESSION) -or
($env:TERM_PROGRAM -eq "vscode") -or
($env:VSAPPIDNAME -eq "devenv.exe") -or
($env:ConEmuANSI -eq "ON")
# ----------------------------------------------------------------------------
# 2. HEADER BANNER
# ----------------------------------------------------------------------------
if ($hasValidWindow) {
$width = $Host.UI.RawUI.WindowSize.Width
$time = Get-Date -Format "HH:mm:ss"
$user = $env:USERNAME.ToUpper()
if ($supportsNerdFonts) {
$copilotIcon = [char]::ConvertFromUtf32(0xF166A)
$userIcon = [char]::ConvertFromUtf32(0xF489)
$clockIcon = [char]::ConvertFromUtf32(0xF1425)
} else {
$copilotIcon = "[BOT]"
$userIcon = ">"
$clockIcon = "@"
}
if ($script:isCopilot) {
$leftLabel = " $copilotIcon COPILOT AGENT "
$modeColor = "38;5;39"
} else {
$leftLabel = " $userIcon $user "
$modeColor = "38;5;99"
}
$rightLabel = " $time $clockIcon "
$fillCount = $width - $leftLabel.Length - $rightLabel.Length
$fillLine = if ($fillCount -gt 0) { [string]::new([char]0x2501, $fillCount) } else { "" }
Write-Host ""
Write-Host "`e[1;$($modeColor)m$leftLabel`e[0m`e[38;5;236m$fillLine`e[0m`e[90m$rightLabel`e[0m"
Write-Host ""
}
# ----------------------------------------------------------------------------
# 3. EARLY EXIT FOR NON-INTERACTIVE TERMINALS
# ----------------------------------------------------------------------------
if ($isNonInteractive) { return }
# ----------------------------------------------------------------------------
# 4. INTERACTIVE UI SETUP
# ----------------------------------------------------------------------------
if ($script:isCopilot) {
function global:prompt {
$Host.UI.RawUI.WindowTitle = "VS 2026 | Copilot"
"PS $($PWD.Path)> "
}
} else {
if (Get-Module -ListAvailable -Name PSReadLine) {
Import-Module PSReadLine -ErrorAction SilentlyContinue
Set-PSReadLineOption -PredictionSource History -ErrorAction SilentlyContinue
Set-PSReadLineOption -PredictionViewStyle ListView -ErrorAction SilentlyContinue
}
if (Get-Command oh-my-posh -ErrorAction SilentlyContinue) {
$poshTheme = "$env:POSH_THEMES_PATH\marcduiker.omp.json"
if (Test-Path $poshTheme) {
oh-my-posh init pwsh --config $poshTheme | Invoke-Expression
}
}
}
# ----------------------------------------------------------------------------
# 5. ENCODING
# ----------------------------------------------------------------------------
$OutputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
Prerequisites
For the full experience:
- Oh My Posh:
winget install JanDeDobbeleer.OhMyPosh - A Nerd Font: Download from nerdfonts.com and configure in your terminal
- Windows Terminal (recommended):
winget install Microsoft.WindowsTerminal
Customization Tips
- Change the theme to your preferred Oh My Posh theme
- Adjust the colors by modifying the ANSI codes (
38;5;39for blue,38;5;99for purple) - Add additional detection methods if you use other AI tools
What It Looks Like
When Copilot is active (with Nerd Fonts):
[robot-icon] COPILOT AGENT ━━━━━━━━━━━━━━━━━━━━━━━━━ 14:32:15 [clock-icon]
When you’re in control:
> YOURNAME ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14:32:15 [clock-icon]
(The actual icons render beautifully with Nerd Fonts installed!)
Conclusion
This small addition to your PowerShell profile makes it immediately clear whether you’re looking at a terminal session you control or one being operated by an AI assistant. It’s a simple quality-of-life improvement that becomes invaluable when working with modern AI-assisted development tools.
Feel free to adapt this to your needs - and share your improvements in the comments!
This article is also published on my personal blog: Detecting AI Agent Terminals in PowerShell
Tuesday, 9 December 2025
BBC Website Dark Mode HOWTO
It's December 2025 and the BBC website at https://www.bbc.co.uk/ still doesn't have automatic dark mode detection. In an era where virtually every major website respects the prefers-color-scheme media query, the BBC continues to blast users with a bright white interface regardless of their OS settings.
The frustrating part? It would be trivially easy for them to add. The CSS @media (prefers-color-scheme: dark) query has been widely supported since 2019. Six years later, we're still waiting.
The DIY Fix: Stylus Browser Extension
Until the BBC catches up with the rest of the internet, you can fix it yourself using the Stylus browser extension. Here's how:
Step 1: Install Stylus
Install the Stylus extension for your browser:
Step 2: Create a New Style
- Click the Stylus extension icon in your browser toolbar
- Click "Manage" to open the Stylus dashboard
- Click "Write new style" (or the + button)
- Give it a name like "BBC Dark Mode"
Step 3: Configure the URL Pattern
Important: You need to set this style to apply to all BBC pages. In the style editor:
- Click "Specify" next to "Applies to"
- Select "URLs starting with"
- Enter:
https://www.bbc.co.uk/
Step 4: Paste the CSS
Copy and paste the following CSS into the code editor:
/* This media query checks the user's OS preference */
@media (prefers-color-scheme: dark) {
/* 1. Base Colors: Set the background of the whole page and the main text color */
body {
background-color: #121212 !important; /* Dark gray background */
color: #e0e0e0 !important; /* Light gray text */
}
/* 2. Primary Containers: Override white backgrounds on main content blocks, HEADER, NAV, FOOTER, and individual news cards */
header,
nav,
footer,
article,
aside,
.nw-c-most-read-list,
.gs-c-promo-body, /* Targets the body of a promotional card */
.gs-c-promo, /* Targets the promotional card itself */
.nw-o-keyline, /* Targets common section separators/containers */
.ssrcss-11vwucc-Container, /* Targets the specific content wrapper shown in Dev Tools */
.ssrcss-1b2q7d0-GridItem, /* Targets a common list/grid item container */
.ssrcss-17p825a-StyledWrapper, /* Targets another common section wrapper */
.ssrcss-1pm1h7u-StyledBorders, /* Ensure background behind bordered elements is dark */
.ssrcss-17c37qf-StyledBorders, /* Ensure background behind bordered elements is dark */
.ssrcss-1yv54b, /* Example of a potential main article wrapper class */
.ssrcss-17lvw4x-GridContainer, /* Example of a potential grid container */
.ssrcss-vy1h6s-GlobalNavigationContainer, /* Targets large global navigation/content wrapper */
.ssrcss-1k5z96v-Container, /* Targets the main grid/story wrapper */
.ssrcss-de737q-Container, /* Targets the recurring child div content containers */
*:not(img):not(svg) { /* NEW: Highly specific fix for any element with an explicit white background */
background-color: #1a1a1a !important;
}
[role="main"] {
background-color: #1a1a1a !important;
color: #e0e0e0 !important;
}
/* 3. Article Text and Headings: Ensure all foreground text is readable */
h1, h2, h3, p, span {
color: #f0f0f0 !important;
}
/* 4. Links: Change default blue/black links to a lighter, readable color */
a:link, a:visited {
color: #8ab4f8 !important; /* A light blue for contrast */
}
/* 4b. Specific Navigation Links: Ensure navigation text (e.g., "News", "UK") is white against the dark header */
nav a,
header a,
.ssrcss-rrm6an-RichTextContainer,
.ssrcss-1j1rzn0-Stack {
color: #f0f0f0 !important;
}
/* 5. Borders: If borders exist, make them slightly darker than the background */
.ssrcss-1pm1h7u-StyledBorders, .ssrcss-17c37qf-StyledBorders {
border-color: #333333 !important;
}
/* 6. Image Background Fix: Prevent white flash when images are loading or transparent */
img,
.ssrcss-153qrb0-ImageWrapper { /* Targets the image element and a common BBC image wrapper */
background-color: #1a1a1a !important;
}
/* 7. Forms */
input,
textarea,
button,
.ssrcss-w94gox-TextAreaWrapper {
color: #f0f0f0 !important;
border-color: #777 !important;
}
}
Step 5: Save
Click "Save" (or press Ctrl+S). The style will immediately apply to any open BBC tabs.
The Result
Now when you visit bbc.co.uk with your OS set to dark mode, you'll get a proper dark theme instead of being blinded by white backgrounds.
Dear BBC...
This CSS took about 5 minutes to write. You have a team of developers. Please just add dark mode support. It's 2025. Thank you.
Github Copilot's problem with Powershell Here-strings
Problem
When GitHub Copilot (or similar AI coding assistants) uses run_command_in_terminal with PowerShell here-strings (@‘…’@ or @“…”@), the terminal enters continuation mode and hangs indefinitely, waiting for input that never comes.
Symptoms
• Terminal shows >> prompts repeatedly
• Command never completes
• Task eventually times out or must be cancelled with Ctrl+C
Root Cause
PowerShell here-strings require:
- The opening delimiter (@’ or @") at the end of a line
- Content on subsequent lines
- The closing delimiter ('@ or "@) at the start of its own line
When the AI sends multi-line commands through terminal automation, line breaks aren’t preserved correctly, causing PowerShell to wait forever for the closing delimiter.
Solution: Add to copilot-instructions.md
Add this to your repository’s .github/copilot-instructions.md:
## ⚠️ Terminal Command Limitations
### NEVER Use PowerShell Here-Strings in Terminal Commands
When using `run_command_in_terminal`, **NEVER** use PowerShell here-strings (`@'...'@` or `@"..."@`). They cause the terminal to hang.
### ✅ Alternatives:
1. **For file edits**: Use the `edit_file` tool (preferred)
2. **For simple replacements**: Use single-line `-replace` with escaped patterns
3. **For complex changes**: Provide code to the user to paste manually
4. **If terminal is needed**: Write content to a temp file first
Key Takeaway
AI assistants should never use PowerShell here-strings in terminal commands. Always prefer dedicated file editing tools or provide code snippets for manual pasting when multi-line content is involved.
Sunday, 7 December 2025
Toggl have crippled their API
It seems that Toggl have crippled their API by limiting even customers paying several thousand dollars a year to 600 calls per hour.
PER HOUR!
This unfortunately makes Toggl useless to us, as we are unable to execute HR reports or simple system integrations in a reasonable amount of time. We are currently looking around for alternatives.
Commonly-used Copilot phrases
Nuget publish script
Create "Publish.ps1" a script in the solution root that completes each of the following steps, stopping if any fails:
- Check for git porcelein
- Determine the Nerdbank git version
- Check that nuget-key.txt exists, has content and is gitignored
- Run unit tests (unless -SkipTests is specified)
- Publish to nuget.org
The script should not interact with the user. It should exit with 0 if successful.