Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Cross Platform

ASecurity

Cross-platform pitfalls for shell handling, paths, and file operations

116 stars
0 votes
0 copies
0 views
Added 9/22/2026
developmentrustgoshellbashnodedockertestinggitapisecurity

Works with

claude codeterminalcliapi

Security Analysis

A100/100

Scanned 9/22/2026

Install to Claude Code

$npx -y skills add Kangentic/kangentic --skill cross-platform --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cross Platform?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Cross Platform
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/kangentic-cross-platform/badge)](https://www.skillsdirectory.com/skills/kangentic-cross-platform)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
description: Cross-platform pitfalls for shell handling, paths, and file operations
---

# Cross-Platform Pitfalls

Contextual knowledge for platform-specific issues across Windows, macOS, and Linux. Reference this skill when working on shell handling, path utilities, terminal rendering, or file operations.

## Shell Resolution

`src/main/pty/spawn/shell-resolver.ts` discovers available shells per platform:

**Windows priority:** PowerShell 7 -> PowerShell 5 -> Git Bash -> cmd.exe, plus WSL distros via `wsl --list --quiet` (5-second timeout, Docker distros filtered out).

**macOS priority:** zsh -> bash -> fish -> nushell -> sh

**Linux priority:** bash -> zsh -> fish -> dash -> nushell -> ksh -> sh

**Default shell fallback:** Windows uses hierarchy search (pwsh -> powershell -> bash -> cmd). Unix uses `$SHELL` env var, then zsh (macOS) or bash (Linux), then `/bin/sh`.

## Per-Shell Adaptations

When spawning a PTY session, the shell type determines command construction:

| Shell | Adaptation | Source |
|-------|-----------|--------|
| PowerShell (pwsh/powershell) | Prefix executable with `& ` call operator | `adaptCommandForShell` (`src/shared/paths.ts`) |
| WSL (`wsl -d <distro>`) | Split into exe (`wsl.exe`) + args (`-d`, distro) only - the `.exe` is appended because node-pty's ConPTY resolver cannot find an extension-less bare name; the agent command is NOT in argv, it is written into the PTY afterwards through `adaptCommandForShell`, which converts the leading exe path to `/mnt/c/...` | `resolveShellArgs` (`src/main/pty/spawn/pty-spawn.ts`), `adaptCommandForShell` (`src/shared/paths.ts`) |
| Fish | Skip `--login` flag | `resolveShellArgs` (`src/main/pty/spawn/pty-spawn.ts`) |
| Nushell | Skip `--login` flag | `resolveShellArgs` (`src/main/pty/spawn/pty-spawn.ts`) |
| Git Bash | Convert the leading Windows exe path to `/c/Users/...` format | `convertWindowsExePath` (`src/shared/paths.ts`) |

## Path Handling

`src/shared/paths.ts` provides platform-safe path utilities:

- **`toForwardSlash(path)`** - Replace backslashes with forward slashes. Required for all paths written to `.claude.json` or config files, as Claude Code uses forward slashes on all platforms.
- **`quoteArg(arg, shell?, { multiline? })`** - Shell-aware quoting, keyed on the TARGET shell, not the host platform: unix-like shells (bash, zsh, WSL) get single quotes with `'\''` escaping; PowerShell/cmd get double quotes with backtick/`$`/`"` escaping. When `shell` is omitted, falls back to platform detection (win32 = double quotes). Simple args (matching `/^[a-zA-Z0-9_.\/:-]+$/`) left unquoted; a backslashed Windows path is never simple, so it is always quoted. `{ multiline: true }` keeps newlines in prompt-style content: literal inside `'...'` for unix-like shells, backtick-n escapes inside `"..."` for PowerShell, flattened for cmd. A bare `--` is emitted as `"--"` for PowerShell hosts (its binder eats an unquoted one before a `.ps1` sees `$args`).
- **`isPowerShellShell(shell)`** - The PowerShell-family predicate (`powershell` / `pwsh` substring), the exact negation `isUnixLikeShell` applies. Use it instead of an inline `includes()` pair.
- **`convertWindowsExePath(cmd, isWsl)`** - Converts the leading Windows exe path of a command string to POSIX form (`/c/...` or `/mnt/c/...`), recognizing bare, double-quoted, and single-quoted leading tokens (single quotes are what `quoteArg` emits for unix-like shells; a single-quoted token stays single-quoted so shell-active path characters remain inert). Called via `adaptCommandForShell` at the PTY spawn seam.
- **`toGitBashPath(path)`** - `C:\Users\dev` -> `/c/Users/dev`
- **`toWslPath(path)`** - `C:\Users\dev` -> `/mnt/c/Users/dev`
- **`sanitizeForPty(text)`** - Collapse newlines/tabs/consecutive whitespace to single space. Prevents newlines being interpreted as Enter by terminal emulators.

## PowerShell Prompt Escaping

`src/main/agent/adapters/claude/command-builder.ts` (the prompt block of `buildClaudeCommand`):

PowerShell interprets `\"` differently from bash. The command builder replaces double quotes with single quotes in prompts BEFORE `quoteArg()` wrapping. Without this, prompts containing quotes break PowerShell sessions.

Additionally, `--` (end-of-options) is inserted before the prompt to prevent content like `->` or `--flag` from being parsed as CLI options. It goes through `quoteArg('--', shell)`, which emits `"--"` for PowerShell hosts; see the next section for why.

## PowerShell, Git Bash, and npm `.cmd` shims

An npm-installed agent CLI resolves on PATH to its `.cmd` shim (`which` walks PATHEXT). Running a `.cmd` routes through cmd.exe, whose command line ends at the first newline, so the multi-line `{{task_xml}}` prompt reached the agent as `<task>` alone (#353) under PowerShell and Git Bash alike; a cmd host is already flattened by `quoteArg`. `resolveShimLaunch` (`src/main/agent/shared/shim-launch.ts`) runs at every spawn chokepoint after `ensureTrust` and before `buildCommand`: on Windows with a `.cmd` / `.bat` head it launches the sibling shim npm writes beside it, the `.ps1` for PowerShell (gated on the host's `Get-ExecutionPolicy` allowing scripts, probed once per shell per run) or the extensionless `#!/bin/sh` script for Git Bash. With no usable sibling it keeps the `.cmd` and flattens the prompt with `sanitizeForPty`, warning once. PowerShell's binder consumes a bare `--` before a `.ps1` sees `$args`, which is why `quoteArg` quotes that marker. Full contract: `docs/cross-platform.md`.

## Windows File Operations

Windows holds file handles longer than Unix after process termination. This affects worktree cleanup:

**Retry pattern** (`src/main/git/worktree-manager.ts`, `removeWorktree`):
```
1. git worktree remove --force (release git's tracking + directory)
2. On failure, fall back to async fs.promises.rm with built-in retries:
     { recursive: true, force: true, maxRetries: 10, retryDelay: 200 }
3. On final failure, best-effort `git worktree prune` so metadata stays
   consistent even if the directory survived.
```

The `maxRetries` / `retryDelay` parameters give the kernel up to 2s total
(10 * 200ms) to release handles on Windows NTFS (EBUSY, ENOTEMPTY, EPERM).
Async `fs.promises.rm` is required (not `fs.rmSync`) so the main process
event loop stays responsive during bulk operations - hundreds of
sequential sync deletes would freeze the UI.

Always use `{ force: true }` on Windows -- never plain recursive removal
which throws EPERM on locked files.

## Em-Dash Encoding

**NEVER use Unicode em-dash (U+2014) anywhere in the codebase.** Always use a single ASCII `-` instead; the en-dash (U+2013) and `--` as punctuation are equally banned (see `.claude/rules/writing-style.md`).

Windows console code pages (e.g., CP437, CP1252) cannot render em-dashes, producing garbled characters like `\u0096` or mojibake. This applies to:
- Source code and comments
- Test assertions and descriptions
- Documentation and markdown
- CLI output and error messages
- Template strings passed to Claude Code

## Git Commands

**Always use `git -C <path>`** for git commands in other directories. Never use `cd <path> && git ...` -- this triggers an unbypasable Claude Code security prompt.

## xterm.js Terminal Rendering

`src/renderer/hooks/useTerminal.ts`:

### WebGL Context Loss Recovery
```
1. Attempt WebGL renderer (lines 70-79)
2. On context loss -> dispose WebGL addon
3. Fallback to canvas renderer (automatic)
```

No manual recreation needed -- xterm.js falls back to canvas automatically after WebGL disposal.

### Font Preloading
Terminal font must be loaded before xterm initialization. If the font isn't ready, xterm measures characters incorrectly, causing misaligned TUI output.

### Resize Debouncing
PTY resize calls are debounced at 200ms (`useTerminal.ts`, lines 8-11, 90-99). This prevents:
- Scrollback buffer eviction from rapid row-count changes during panel drag
- TUI redraw churn during window resize
- Resize suppression during active scrollback replay (lines 138-143)

### Scrollback Replay
When a terminal reconnects (dialog close -> panel recreate):
1. Load scrollback buffer from session
2. Write to xterm
3. Fit after replay completes
4. Force explicit resize to sync PTY dimensions (initial 120x30 likely differs from container)
5. Drop duplicate `onData` during load via `scrollbackPendingRef`

## Electron E2E Testing

`_electron.launch()` on Windows always opens a real window -- there is no headless mode for Electron E2E tests. Tests that need headless use the UI test tier with `mock-electron-api.js` instead.

## Worktree Path Detection

`src/main/git/worktree-manager.ts` (lines 35-44):

Checks `parent=worktrees` and `grandparent=.kangentic` to verify a path is inside a Kangentic-managed worktree. Normalizes all separators to forward slashes (`replace(/\\/g, '/')`) before splitting, so it works on both Windows and Linux.

**IMPORTANT:** Never use `path.normalize()`, `path.dirname()`, or `path.basename()` on paths that may contain Windows backslashes when the code runs on Linux. Node's `path` module is platform-dependent -- on Linux, `\` is a valid filename character, not a separator. Always normalize slashes manually first.

Sparse-checkout excludes `.claude/commands/` from worktrees (commands walk up the directory tree, so including them would cause duplicate discovery). Skills and agents do NOT walk up, so they must be present in the worktree checkout.

## Key Source Files

- `src/main/pty/spawn/shell-resolver.ts` - Shell discovery and default selection
- `src/main/agent/shared/shim-launch.ts` - Sibling-shim selection for a `.cmd` / `.bat` head under PowerShell or Git Bash, with the prompt-flatten fallback
- `src/main/agent/adapters/claude/command-builder.ts` - Claude CLI command assembly, prompt sanitization
- `src/main/git/worktree-manager.ts` - Worktree CRUD with Windows retry logic
- `src/renderer/hooks/useTerminal.ts` - xterm setup, WebGL fallback, resize debouncing
- `src/shared/paths.ts` - Path normalization, shell-aware quoting, PTY sanitization

Attribution

KangenticKangentic
View sourceMore from Kangentic →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

284072 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2192 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →