Laptops are unreliable for interviews — passwords missing, software not installed, candidate artifacts visible from previous interviews, no clear ownership, interviewers scrambling to use personal machines.
Split responsibility between Kandji (IT-managed, slow-changing) and a git repo (eng-managed, fast-changing).
Kandji (IT owns) Git repo (eng owns)
──────────────── ────────────────────
macOS updates Interview repo list + git clone
Homebrew SSH keys (SOPS-encrypted)
Chrome, VS Code, Cursor, iTerm, Zoom Anthropic API key (SOPS-encrypted)
Xcode CLI tools Claude Code config
Node (nvm), Python (uv) GitHub CLI auth
Admin user setup .gitconfig, .zshrc
1Password app Desktop shortcut scripts
Age secret key placement Repo-specific tooling
Kandji handles base image + software. The git repo handles everything engineers need to change without an IT ticket.
| Credential | Where It Lives | Who Manages |
|---|---|---|
| Laptop login password | Sticker on laptop (short term), Kandji (long term) | IT |
eng-interview@gamma.app password |
1Password vault ("Interview Laptops") | IT |
| GitHub token / SSH keys | SOPS in git repo | Engineers |
| Anthropic API key | SOPS in git repo | Engineers |
| Age decryption key | Placed by Kandji blueprint | IT (one-time) |
SOPS + age for machine-consumed secrets (API keys, tokens). Engineers edit via sops secrets/secrets.sops.yml, commit, and laptops pull on next update.
1Password vault (dedicated, separate from company vault) for human-consumed secrets (account passwords, login URLs).
gamma-app/interview-laptop/
├── secrets/
│ ├── .sops.yaml # age public key config
│ └── secrets.sops.yml # encrypted: API keys, GitHub token, SSH key
├── repos.yml # list of repos to clone
├── scripts/
│ ├── update.sh # provision/update the laptop
│ ├── reset.sh # clean up after a candidate
│ └── setup-desktop.sh # place .command shortcuts on Desktop
├── dotfiles/
│ ├── .gitconfig
│ └── .zshrc.interview
└── README.md
Three .command files on the Desktop (double-clickable by non-engineers):
Pulls latest config from git, decrypts secrets, auths GitHub, clones/updates interview repos.
#!/bin/bash
set -euo pipefail
REPO_DIR="$HOME/interview-laptop"
LOG="$HOME/Desktop/last-update.log"
echo "=== Updating interview laptop ===" | tee "$LOG"
# Clone or pull the config repo
if [ -d "$REPO_DIR" ]; then
cd "$REPO_DIR" && git pull | tee -a "$LOG"
else
git clone git@github.com:gamma-app/interview-laptop.git "$REPO_DIR"
cd "$REPO_DIR"
fi
# Decrypt secrets
brew install sops age 2>/dev/null || true
export SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt"
SECRETS=$(sops -d secrets/secrets.sops.yml)
# Anthropic API key
mkdir -p "$HOME/.config/claude"
API_KEY=$(echo "$SECRETS" | yq '.anthropic_api_key')
echo "export ANTHROPIC_API_KEY=\"$API_KEY\"" > "$HOME/.zshrc.interview-secrets"
chmod 600 "$HOME/.zshrc.interview-secrets"
grep -q 'zshrc.interview-secrets' "$HOME/.zshrc" || \
echo 'source "$HOME/.zshrc.interview-secrets"' >> "$HOME/.zshrc"
# GitHub CLI auth
echo "$SECRETS" | yq '.github_token' | gh auth login --with-token
# Clone/update interview repos
REPOS=$(yq '.repos[]' repos.yml)
mkdir -p "$HOME/interview-repos"
for repo in $REPOS; do
dest="$HOME/interview-repos/$(basename "$repo")"
if [ -d "$dest" ]; then
(cd "$dest" && git checkout main && git pull)
else
git clone "git@github.com:gamma-app/$repo.git" "$dest"
fi
done
echo "" | tee -a "$LOG"
echo "=== Update complete! ===" | tee -a "$LOG"
read -p "Press Enter to close..."Cleans up candidate work. Non-engineers (Karen) can double-click this.
#!/bin/bash
set -euo pipefail
echo "=== Resetting interview laptop ==="
echo "Cleaning up all candidate work..."
echo ""
# Reset all interview repos to clean main
for dir in "$HOME/interview-repos"/*/; do
[ -d "$dir/.git" ] || continue
name=$(basename "$dir")
echo "Cleaning $name..."
cd "$dir"
git checkout main 2>/dev/null || git checkout master
git branch | grep -v '^\*' | grep -v 'main' | grep -v 'master' | xargs -r git branch -D
git clean -fd
git checkout .
cd - > /dev/null
done
# Clear editor workspace state
rm -rf "$HOME/Library/Application Support/Code/User/workspaceStorage"/* 2>/dev/null
rm -rf "$HOME/Library/Application Support/Cursor/User/workspaceStorage"/* 2>/dev/null
# Clear browser history + cookies
rm -f "$HOME/Library/Application Support/Google/Chrome/Default/History" 2>/dev/null
rm -f "$HOME/Library/Application Support/Google/Chrome/Default/Cookies" 2>/dev/null
# Clear shell history
rm -f "$HOME/.zsh_history" "$HOME/.bash_history"
# Clear Downloads
rm -rf "$HOME/Downloads"/* 2>/dev/null
echo ""
echo "=== Reset complete! Ready for next candidate. ==="
read -p "Press Enter to close..."#!/bin/bash
open "x-1password://vault/interview-laptops"Engineers edit this to add/remove interview repos. No IT ticket needed.
repos:
- intw-frontend-challenge
- intw-backend-challenge
- intw-ai-coding
- intw-data-challenge1. git clone gamma-app/interview-laptop
2. Edit repos.yml, secrets.sops.yml, or scripts/
3. Open PR → review → merge
4. Next "Update Laptop" click on any machine pulls the change
Dennis configures this in Kandji. One-time setup, rarely changes.
Software to install:
- Homebrew
- Git, gh CLI
- nvm + Node 22, uv + Python 3.12
- Chrome, VS Code, Cursor, iTerm2, Zoom, 1Password
- Xcode CLI tools
- sops, age
Config to apply:
- Place age secret key at
~/.config/sops/age/keys.txt - Enable Remote Login (SSH) for remote management
- Enable Power Nap (so Kandji updates apply while lid is closed + plugged in)
- Create admin user with standard interview password
- Clone
gamma-app/interview-laptopand runscripts/setup-desktop.sh
- Create a GitHub team:
interview-laptop-users - Create a shared SSH keypair, add public key to the team's GitHub account (
eng-interview@gamma.app) - Private key goes in SOPS (
secrets.sops.yml) - All interview repos use
INTW-prefix naming convention - The team gets read access to all
INTW-*repos
Laptops stored in cubby with lids closed won't receive Kandji updates by default.
Fix: Enable Power Nap in the Kandji blueprint (System Settings → Battery → Options → Wake for network access). As long as laptops are plugged into the power strip in the cubby, Kandji can push updates with the lid closed.
- Cubby near interview rooms with power strip + extension cord
- Manila file holders to organize laptops vertically
- Remove demo stickers (avoid confusion with sales/marketing demo machines)
- Label each laptop (Interview 1, 2, 3, 4)
Interview ends
│
▼
Interviewer (or Karen) double-clicks "2-Reset-Laptop.command"
│
▼
Script cleans repos, browser history, shell history, downloads
│
▼
Laptop goes back in cubby, plugged in
- M1 laptop — too old? Replace with M2+ from eng refresh hand-me-downs?
- 4 laptops enough or need 6 for new office?
- Deep Freeze worth it or is the reset script sufficient?
- Browser-based interviews (CoderPad/CodeSandbox) as long-term replacement?