Skip to content

Instantly share code, notes, and snippets.

@bkaney
Created February 12, 2026 14:07
Show Gist options
  • Select an option

  • Save bkaney/4b9e7ef9816f168eac064512fa3e1f49 to your computer and use it in GitHub Desktop.

Select an option

Save bkaney/4b9e7ef9816f168eac064512fa3e1f49 to your computer and use it in GitHub Desktop.
Helper script for consultants or anyone juggling multiple client projects who wants to launch VS Code with a client-specific profile—keeping settings, Copilot access, and AI subscriptions cleanly isolated.
#!/usr/bin/env bash
set -euo pipefail
# code-client: launch VS Code with per-client user-data-dir based on
# ~/projects/{client}/{project} hierarchy.
PROJECTS_ROOT="${PROJECTS_ROOT:-$HOME/projects}"
CODE_BIN="${CODE_BIN:-code}"
usage() {
cat <<'EOF'
Usage:
code-client [path] [--no-isolation] [--client NAME] [--project-root]
Examples:
cd ~/projects/acme/app1 && code-client
code-client ~/projects/acme/app1
code-client --no-isolation .
code-client --client acme ~/projects/acme/app2
Env:
PROJECTS_ROOT defaults to ~/projects
CODE_BIN defaults to "code"
EOF
}
NO_ISOLATION=0
FORCE_CLIENT=""
OPEN_PROJECT_ROOT=0
ARGS=()
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help) usage; exit 0 ;;
--no-isolation) NO_ISOLATION=1; shift ;;
--client) FORCE_CLIENT="${2:-}"; shift 2 ;;
--project-root) OPEN_PROJECT_ROOT=1; shift ;;
--) shift; ARGS+=("$@"); break ;;
*) ARGS+=("$1"); shift ;;
esac
done
TARGET_PATH="${ARGS[0]:-.}"
TARGET_PATH="$(cd "$TARGET_PATH" 2>/dev/null && pwd || true)"
if [[ -z "$TARGET_PATH" ]]; then
echo "Could not resolve path: ${ARGS[0]:-.}" >&2
exit 2
fi
if [[ "$NO_ISOLATION" -eq 1 ]]; then
exec "$CODE_BIN" "$TARGET_PATH"
fi
# Normalize root for matching
PROJECTS_ROOT="$(cd "$PROJECTS_ROOT" && pwd)"
# Determine client/project from path
# Expected: $PROJECTS_ROOT/<client>/<project>/...
rel="${TARGET_PATH#"$PROJECTS_ROOT"/}"
client=""
project=""
if [[ "$TARGET_PATH" == "$PROJECTS_ROOT"* && "$rel" != "$TARGET_PATH" ]]; then
client="$(cut -d'/' -f1 <<<"$rel")"
project="$(cut -d'/' -f2 <<<"$rel")"
fi
if [[ -n "$FORCE_CLIENT" ]]; then
client="$FORCE_CLIENT"
# If forcing client, open whatever target path user gave (unless --project-root)
fi
# If we can't determine a client, just open normally.
if [[ -z "$client" || "$client" == "." || "$client" == ".." ]]; then
exec "$CODE_BIN" "$TARGET_PATH"
fi
CLIENT_DIR="$PROJECTS_ROOT/$client"
USER_DATA_DIR="$CLIENT_DIR/.vscode-user-data"
mkdir -p "$USER_DATA_DIR"
OPEN_PATH="$TARGET_PATH"
if [[ "$OPEN_PROJECT_ROOT" -eq 1 && -n "$project" && "$project" != "$client" ]]; then
OPEN_PATH="$PROJECTS_ROOT/$client/$project"
else
# If inside a client tree and we detected a project, default to project root.
if [[ -n "$project" && "$project" != "$client" ]]; then
OPEN_PATH="$PROJECTS_ROOT/$client/$project"
fi
fi
exec "$CODE_BIN" --user-data-dir="$USER_DATA_DIR" "$OPEN_PATH"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment