Initial Warp dotfiles: configs + symlink installer

Co-Authored-By: Oz <oz-agent@warp.dev>
This commit is contained in:
tevans
2026-06-18 20:51:18 +01:00
co-authored by Oz
commit aa291cc545
6 changed files with 340 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
# Backups created by install.ps1
*.bak-*
*.bak
# OS / editor cruft
Thumbs.db
Desktop.ini
.DS_Store
+81
View File
@@ -0,0 +1,81 @@
# warp-dotfiles
Version-controlled [Warp](https://www.warp.dev/) configuration, symlinked into
place on each machine so file-based settings follow me everywhere.
This complements — it does not replace — Warp's cloud features:
- **Settings Sync** (cloud) handles themes, AI settings, feature toggles, and
privacy settings automatically on login.
- **Warp Drive Workflows** (cloud) store reusable, parameterized commands
(e.g. SSH connections).
- **This repo** captures the file-based bits Settings Sync skips: custom
keybindings, custom themes, YAML/tab configs, and local `settings.toml`.
## Layout
```
warp-dotfiles/
├── install.ps1 # symlink installer (Windows / PowerShell)
├── README.md
└── warp/
├── data/ # -> %APPDATA%\warp\Warp\data
│ ├── keybindings.yaml # custom keybindings (if present)
│ ├── tab_configs/ # launch / tab configs (TOML)
│ └── themes/ # custom themes
└── config/ # -> %LOCALAPPDATA%\warp\Warp\config
└── settings.toml # device settings
```
## Symlink mapping
| Repo path | Target on Windows |
| ------------------------------- | ----------------------------------------------- |
| `warp\data\tab_configs` | `%APPDATA%\warp\Warp\data\tab_configs` |
| `warp\data\themes` | `%APPDATA%\warp\Warp\data\themes` |
| `warp\data\keybindings.yaml` | `%APPDATA%\warp\Warp\data\keybindings.yaml` |
| `warp\config\settings.toml` | `%LOCALAPPDATA%\warp\Warp\config\settings.toml` |
Entries whose source does not exist in the repo are skipped, so the script is
safe to run even before you've added keybindings or themes.
> Note: `settings.toml` includes some device-specific values (e.g. startup
> shell). If you don't want it shared across machines, remove that entry from
> `$Entries` in `install.ps1`.
## Set up on a new machine
1. Enable **Developer Mode** so non-admin symlink creation works:
Settings > Privacy & security > For developers > Developer Mode.
(Alternatively, run the installer from an elevated PowerShell.)
2. Clone and run:
```powershell
git clone https://github.com/<you>/warp-dotfiles.git $env:USERPROFILE\warp-dotfiles
cd $env:USERPROFILE\warp-dotfiles
pwsh -ExecutionPolicy Bypass -File .\install.ps1
```
3. Restart Warp.
### Useful flags
```powershell
pwsh -File .\install.ps1 -DryRun # preview changes, write nothing
pwsh -File .\install.ps1 -Force # delete existing real targets instead of backing them up
```
Existing real files at a target are backed up to `<target>.bak-<timestamp>`
unless `-Force` is used.
## Updating
Because the targets are symlinks back into this repo, edits made in Warp land
directly in the working tree. Commit and push as usual:
```powershell
cd $env:USERPROFILE\warp-dotfiles
git add -A
git commit -m "Update Warp config"
git push
```
+132
View File
@@ -0,0 +1,132 @@
<#
.SYNOPSIS
Symlinks Warp configuration files from this dotfiles repo into the
locations Warp reads on Windows.
.DESCRIPTION
For each managed entry, the script:
* Ensures the target's parent directory exists.
* If a real file/dir already lives at the target, backs it up to
"<target>.bak-<timestamp>" (unless -Force is used, which deletes it).
* Replaces an existing symlink at the target.
* Creates a new symlink target -> repo source.
Creating symlinks on Windows requires either:
* Developer Mode enabled (Settings > Privacy & security > For developers), or
* Running this script from an elevated (Administrator) PowerShell.
.PARAMETER DryRun
Print what would happen without making changes.
.PARAMETER Force
Delete existing real targets instead of backing them up.
.EXAMPLE
pwsh -ExecutionPolicy Bypass -File .\install.ps1
pwsh -File .\install.ps1 -DryRun
#>
[CmdletBinding()]
param(
[switch]$DryRun,
[switch]$Force
)
$ErrorActionPreference = 'Stop'
$RepoRoot = $PSScriptRoot
# Resolve Warp config roots. APPDATA = Roaming (data), LOCALAPPDATA = Local (config).
$DataRoot = Join-Path $env:APPDATA 'warp\Warp\data'
$ConfigRoot = Join-Path $env:LOCALAPPDATA 'warp\Warp\config'
# Managed entries: Source is relative to the repo, Target is absolute.
# Type is 'File' or 'Directory' (controls how the symlink is created).
$Entries = @(
@{ Source = 'warp\data\tab_configs'; Target = (Join-Path $DataRoot 'tab_configs'); Type = 'Directory' }
@{ Source = 'warp\data\themes'; Target = (Join-Path $DataRoot 'themes'); Type = 'Directory' }
@{ Source = 'warp\data\keybindings.yaml'; Target = (Join-Path $DataRoot 'keybindings.yaml'); Type = 'File' }
@{ Source = 'warp\config\settings.toml'; Target = (Join-Path $ConfigRoot 'settings.toml'); Type = 'File' }
)
function Test-SymlinkCapability {
# Admin always works.
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($id)
if ($principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
return $true
}
# Otherwise check Developer Mode.
$key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock'
try {
$val = (Get-ItemProperty -Path $key -Name AllowDevelopmentWithoutDevLicense -ErrorAction Stop).AllowDevelopmentWithoutDevLicense
return ($val -eq 1)
} catch {
return $false
}
}
function Backup-Target {
param([string]$Path)
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
$backup = "$Path.bak-$stamp"
Write-Host " backing up existing target -> $backup" -ForegroundColor Yellow
if (-not $DryRun) { Move-Item -LiteralPath $Path -Destination $backup -Force }
}
Write-Host "Warp dotfiles installer" -ForegroundColor Cyan
Write-Host " repo: $RepoRoot"
Write-Host " data root: $DataRoot"
Write-Host " config root: $ConfigRoot"
if ($DryRun) { Write-Host " MODE: DryRun (no changes)" -ForegroundColor Magenta }
Write-Host ""
if (-not (Test-SymlinkCapability)) {
Write-Warning @"
Symlink creation may fail. Enable Developer Mode
(Settings > Privacy & security > For developers > Developer Mode)
or re-run this script from an elevated (Administrator) PowerShell.
"@
}
foreach ($entry in $Entries) {
$source = Join-Path $RepoRoot $entry.Source
$target = $entry.Target
Write-Host ("-> {0}" -f $entry.Source) -ForegroundColor Cyan
if (-not (Test-Path -LiteralPath $source)) {
Write-Host " skip: source does not exist in repo ($source)" -ForegroundColor DarkGray
continue
}
# Ensure parent dir of target exists.
$parent = Split-Path -Parent $target
if (-not (Test-Path -LiteralPath $parent)) {
Write-Host " creating parent dir: $parent"
if (-not $DryRun) { New-Item -ItemType Directory -Force -Path $parent | Out-Null }
}
# Handle anything already at the target.
if (Test-Path -LiteralPath $target) {
$item = Get-Item -LiteralPath $target -Force
$isLink = $item.LinkType -eq 'SymbolicLink' -or [bool]($item.Attributes -band [IO.FileAttributes]::ReparsePoint)
if ($isLink) {
Write-Host " removing existing symlink"
if (-not $DryRun) { (Get-Item -LiteralPath $target -Force).Delete() }
}
elseif ($Force) {
Write-Host " removing existing target (-Force)" -ForegroundColor Yellow
if (-not $DryRun) { Remove-Item -LiteralPath $target -Recurse -Force }
}
else {
Backup-Target -Path $target
}
}
Write-Host " linking $target -> $source" -ForegroundColor Green
if (-not $DryRun) {
New-Item -ItemType SymbolicLink -Path $target -Target $source | Out-Null
}
}
Write-Host ""
Write-Host "Done." -ForegroundColor Cyan
+111
View File
@@ -0,0 +1,111 @@
[privacy]
telemetry_enabled = true
crash_reporting_enabled = true
custom_secret_regex_list = [
{ name = "IPv4 Address", pattern = '\b((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}\b' },
{
name = "IPv6 Address",
pattern = '\b((([0-9A-Fa-f]{1,4}:){1,6}:)|(([0-9A-Fa-f]{1,4}:){7}))([0-9A-Fa-f]{1,4})\b',
},
{ name = "Slack App Token", pattern = '\bxapp-[0-9]+-[A-Za-z0-9_]+-[0-9]+-[a-f0-9]+\b' },
{ name = "Phone Number", pattern = '\b(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}\b' },
{
name = "AWS Access ID",
pattern = '\b(AKIA|A3T|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{12,}\b',
},
{
name = "MAC Address",
pattern = '\b((([a-zA-z0-9]{2}[-:]){5}([a-zA-z0-9]{2}))|(([a-zA-z0-9]{2}:){5}([a-zA-z0-9]{2})))\b',
},
{ name = "Google API Key", pattern = '\bAIza[0-9A-Za-z-_]{35}\b' },
{ name = "Google OAuth ID", pattern = '\b[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com\b' },
{ name = "GitHub Classic Personal Access Token", pattern = '\bghp_[A-Za-z0-9_]{36}\b' },
{ name = "GitHub Fine-Grained Personal Access Token", pattern = '\bgithub_pat_[A-Za-z0-9_]{82}\b' },
{ name = "GitHub OAuth Access Token", pattern = '\bgho_[A-Za-z0-9_]{36}\b' },
{ name = "GitHub User-to-Server Token", pattern = '\bghu_[A-Za-z0-9_]{36}\b' },
{ name = "GitHub Server-to-Server Token", pattern = '\bghs_[A-Za-z0-9_]{36}\b' },
{ name = "Stripe Key", pattern = '\b(?:r|s)k_(test|live)_[0-9a-zA-Z]{24}\b' },
{ name = "Firebase Auth Domain", pattern = '\b([a-z0-9-]){1,30}(\.firebaseapp\.com)\b' },
{ name = "JWT", pattern = '\b(ey[a-zA-z0-9_\-=]{10,}\.){2}[a-zA-z0-9_\-=]{10,}\b' },
{ name = "OpenAI API Key", pattern = '\bsk-[a-zA-Z0-9]{48}\b' },
{ name = "Anthropic API Key", pattern = '\bsk-ant-api\d{0,2}-[a-zA-Z0-9\-]{80,120}\b' },
{ name = "Generic SK API Key", pattern = '\bsk-[a-zA-Z0-9\-]{10,100}\b' },
{ name = "Fireworks API Key", pattern = '\bfw_[a-zA-Z0-9]{24}\b' },
]
[general]
default_session_mode = "agent"
[agents]
cloud_conversation_storage_enabled = true
[agents.mcp_servers]
file_based_mcp_enabled = true
[agents.warp_agent]
is_any_ai_enabled = true
[agents.warp_agent.input]
nld_in_terminal_enabled = true
ai_auto_detection_enabled = false
[agents.warp_agent.other]
cloud_agent_computer_use_enabled = true
show_conversation_history = true
show_agent_notifications = true
[agents.profiles]
agent_mode_execute_readonly_commands = true
[agents.third_party]
should_render_cli_agent_toolbar = true
[appearance]
[appearance.themes]
system_theme = true
theme = "cyber_wave"
selected_system_themes = { dark = "dark", light = "solarized_dark" }
[appearance.panes]
should_dim_inactive_panes = true
[appearance.input]
input_mode = "waterfall"
[appearance.vertical_tabs]
enabled = true
[notifications]
[notifications.preferences]
is_agent_task_completed_enabled = true
is_long_running_enabled = true
is_needs_attention_enabled = true
is_password_prompt_enabled = true
long_running_threshold = 30
mode = "enabled"
play_notification_sound = true
[code]
[code.indexing]
agent_mode_codebase_context_auto_indexing = true
[code.editor]
show_code_review_button = true
show_global_search = true
show_project_explorer = true
[terminal]
use_audible_bell = true
osc52_clipboard_access = "write_only"
[terminal.input]
input_box_type_setting = "universal"
[account]
is_settings_sync_enabled = true
[warp_drive]
enabled = true
@@ -0,0 +1,8 @@
name = "New tab: tevans"
[[panes]]
id = "main"
type = "terminal"
directory = 'C:\Users\tevans'
[params]
View File