Skip to content

Blackout Secure Dev Setup Kit

Made by BlackoutSecure

Cross-platform developer environment setup for machines without local admin rights.

Installs Git, Node.js, Python, PHP, and PowerShell per-user, then applies VS Code settings that follow you through Settings Sync. Every step auto-detects what is already present and skips it, reporting each decision in the terminal. Nothing requires WSL, sudo, or a GUI installer.

  • Audit first.setup.ps1 -Audit / setup.sh --audit reports what would change and writes nothing.
  • One config. Every tunable lives in config/dev-setup.config.json.
  • Idempotent. Re-running is safe; values are compared before they are written.
  • Color-coded. Each line is tagged [found] (green), [install] (cyan), [warn] (yellow), or [skip] (grey) — identically across PowerShell, bash, and the Python VS Code applier. Colors are suppressed for NO_COLOR, non-TTY output, and are always on under GITHUB_ACTIONS.

Requirements

PlatformNeeds
WindowsPowerShell 5.1+. winget for Node.js, Python, PHP, and PowerShell 7 (falls back to uv for Python).
macOSXcode Command Line Tools for Git. Homebrew for Node.js, PHP, and PowerShell.
Ubuntu / DebianHomebrew is installed under $HOME automatically if missing; used for Git, Node.js, PHP, and PowerShell.

No administrator or root access is required at any point. WSL is never installed or invoked.

Quick start

Windows — setup.cmd is the bootloader; it runs setup.ps1:

.\setup.cmd

macOS / Linux:

chmod +x setup.sh
./setup.sh

Run an audit first to see what would happen:

.\setup.ps1 -Audit
./setup.sh --audit

Audit mode installs nothing, writes no files, and does not touch git config or PATH.

Repository checks

This kit installs machine and editor prerequisites; repositories keep their own pinned Node and Python tooling. From a repository root, use its declared check command. The common patterns in this organization are:

npm run check
python -m pytest -q

Use the repository's package.json, pyproject.toml, or contributor guide as the authority when it differs. Do not install project linters or test runners globally. For Python repositories, create or select the repository virtual environment first; this kit recommends .venv and configures VS Code to discourage global package installs.

Options

OptionApplies toEffect
-Audit / --auditrunners and every installerDetect and report only.
-SkipVSCodeSettingssetup.ps1Leave editor settings alone for one run.
-GitInstallDir <path>setup.ps1Override user.git.installDir for one run.
-PythonVersion <x.y>setup.ps1Override user.python.version for one run.

Audit output

Auditing (detect only - nothing will be installed or changed):
[found] Git git version 2.51.0 at C:\Program Files\Git\cmd\git.exe
[install] git cfg would set credential.helper, credential.credentialStore, credential.guiPrompt
[warn] identity not set; fill user.git.userName / user.git.userEmail
[found] Node.js v22.11.0 at C:\Program Files\nodejs\node.exe
[install] Python would install Python.Python.3.14 via winget
[install] vscode would set 5 setting(s) in <user-profile>\Code\User
- python.globalModuleInstallation
- dev.containers.defaultExtensions
- git.path
- python.defaultInterpreterPath
- python.terminal.activateEnvironment
[skip] validate dry-run; files were not changed
[install] sync would request Settings Sync (stable)
Audit complete. Nothing was installed or changed. Re-run without -Audit to apply.

The same vocabulary is used during a real run:

StatusMeaning
[found]Already present and correct. Nothing was done.
[install]Something was changed or installed.
[skip]Disabled in config, or not applicable on this platform.
[warn]Continued, but the result is degraded or needs your attention.

Layout

setup.cmd Windows bootloader -> setup.ps1
setup.ps1 Windows runner
setup.sh macOS / Linux runner
config/ the single config file you edit
src/ all implementation
src/scripts/ one installer per tool, each runnable on its own
.github/ repo-specific automation config, Dependabot, and CODEOWNERS
PathContents
rootThe entrypoints you actually type. Nothing else.
config/dev-setup.config.jsonSingle source of truth for every setting. Kept at the top level because it is the file you edit.
src/config.ps1, src/config.shConfig loader, dotted-path lookup, status reporter, shared helpers.
src/configure-vscode.pyCross-platform VS Code settings, extensions, and MCP applier.
src/scripts/install-*.{ps1,sh}Per-tool install steps invoked by the runners.
.github/bos-universal-config.jsonRepo-specific Blackout Secure automation config.
.github/dependabot.ymlRepo-specific dependency-update config.
.github/CODEOWNERSRepo-specific review ownership.

Every script resolves the repository root from its own location, so the runners and the individual installers work from any working directory.

Configuration reference

config/dev-setup.config.json has two top-level sections, read by src/config.ps1 (PowerShell), src/config.sh (bash), and src/configure-vscode.py (Python). A value is defined exactly once and cannot drift between platforms.

Every lookup carries a built-in fallback. Deleting a key, leaving it "", or deleting the whole config file degrades to the documented default rather than failing the run.

User-editable recommendations

These are the supported knobs for routine use. They are safe to edit in a fork or personal copy.

SettingDefaultPurpose
user.install.gittrueRun the Git installer step.
user.install.nodetrueRun the Node.js/npm step.
user.install.pythontrueRun the Python step.
user.install.phptrueRun the PHP step. macOS/Linux use Homebrew; Windows uses WinGet.
user.install.powershelltrueRun the PowerShell 7 step. macOS/Linux use Homebrew; Windows uses WinGet.
user.install.vscodeSettingstrueApply any VS Code settings at all.
user.install.devcontainerDefaultstrueInclude the Dev Containers keys and snippet.
user.install.mcpServerstrueReconcile MCP servers in mcp.json.
user.git.installDir""Windows PortableGit location. Empty uses advanced.git.defaultInstallDir.
user.git.forcePortablefalseInstall PortableGit even when a system Git is on PATH. Left false, an existing Git is detected and the download is skipped.
user.git.userName""Applied via git config --global user.name when non-empty.
user.git.userEmail""Applied via git config --global user.email when non-empty.
user.python.version"3.14"Single source of truth for Windows winget and macOS/Linux uv.
user.python.allowGlobalPackageInstallsfalseWritten to VS Code as python.globalModuleInstallation; keep false to preserve the Python extension's virtual-environment warning.
user.python.recommendedVirtualEnvironment".venv"Documented environment folder recommendation for project-level dependencies.
user.vscode.profiles["stable","insiders"]Which VS Code profiles receive settings and extensions.
user.vscode.settingsSync.syncAfterSetuptrueAfter successful validation, request VS Code Settings Sync when it is already enabled.
user.vscode.settingsSync.requiredProvider"github"Only request sync when the signed-in Settings Sync account provider matches this value.
user.vscode.settingscurated set, see belowSettings merged verbatim into settings.json. Wins over everything else.
user.vscode.extensions.managetrueInstall/report extensions at all.
user.vscode.extensions.install17 extensionsInstalled if missing, via the VS Code CLI.
user.vscode.extensions.block11 extensionsNever installed. Reported as [warn] if already present.
user.vscode.extensions.uninstallBlockedfalseWhen true, blocked extensions that are installed are removed instead of just reported.
user.mcp.managetrueReconcile MCP servers at all.
user.mcp.servers4 serversAdded to mcp.json if absent. Existing entries are never overwritten.
user.mcp.inputs[]${input:id} definitions. Required by any server that references one.
user.mcp.block[]Server IDs that should not be configured. Reported as [warn] if present.
user.mcp.removeBlockedfalseWhen true, blocked servers are deleted from mcp.json instead of reported.
user.devcontainers.dockerAccess"outside-of-docker"outside-of-docker, in-docker, or none.
user.devcontainers.baseImagemcr.microsoft.com/devcontainers/base:ubuntu-24.04Image used by the devcontainer snippet.
user.devcontainers.remoteUser"vscode"remoteUser emitted by the snippet.
user.devcontainers.featurescommon-utils, git, github-cliFeatures always installed. The Docker feature is added from dockerAccess.
user.devcontainers.extensionsCopilot, Copilot Chat, PR, Actions, GitLens, EditorConfig, ESLint, Prettier, Ruff, Python, Pylance, debugpy, Markdownlint, Code Spell Checker, Markdown All in One, YAML, ShellCheckExtensions always installed in a container.
user.devcontainers.settingscopyGitConfig, gitCredentialHelperConfigLocation, cacheVolume, logLevelRemaining dev.containers.* keys.

Shared defaults

Shared, derived, or non-auto-detectable values: package identifiers, download URLs, version-pinned paths, state keys, and the setting keys the scripts own. These are public and secret-free, but they are not meant for day-to-day editing.

SettingDefaultPurpose
advanced.git.defaultInstallDir%USERPROFILE%\PortableGitFallback when user.git.installDir is empty.
advanced.git.portableReleaseApiUrlgit-for-windows latest release APIWhere the PortableGit build is discovered.
advanced.git.portableAssetPatternPortableGit-*64-bit.7z.exeWhich release asset to download.
advanced.git.homebrewFormulagitFormula used on macOS/Linux.
advanced.git.homebrewInstallUrlHomebrew install.shUsed only when Homebrew is missing on Linux.
advanced.git.linuxbrewShellenv/home/linuxbrew/.linuxbrew/bin/brewPath used to load brew into the shell after install.
advanced.git.credential.windows.helpermanagerGit Credential Manager.
advanced.git.credential.windows.credentialStorewincredmanWindows Credential Manager backing store.
advanced.git.credential.windows.guiPromptfalseKeeps GCM from opening blocking dialogs.
advanced.git.credential.macos.helperosxkeychainApplied when the helper exists.
advanced.git.credential.linux.helpermanagerApplied when the helper exists.
advanced.python.wingetPackageIdPython.Python.{version}{version} is replaced by user.python.version.
advanced.python.windowsInstallRoot%LOCALAPPDATA%\Programs\PythonWhere an existing interpreter is discovered.
advanced.python.uvInstallUrl.windowshttps://astral.sh/uv/install.ps1uv bootstrap, used only if winget is unavailable.
advanced.python.uvInstallUrl.unixhttps://astral.sh/uv/install.shuv bootstrap on macOS/Linux.
advanced.python.uvWindowsPath%USERPROFILE%\.local\bin\uv.exeWhere the Windows uv bootstrap lands.
advanced.node.wingetPackageIdOpenJS.NodeJS.LTSAlso substituted into windowsSearchPaths.
advanced.node.homebrewFormulanodeFormula used on macOS/Linux.
advanced.node.windowsSearchPaths3 pathsWhere node.exe is located after a winget install. {wingetPackageId} is substituted.
advanced.php.homebrewFormulaphpFormula used on macOS/Linux for PHP validation.
advanced.php.wingetPackageIdPHP.PHPPackage used on Windows for PHP validation.
advanced.powershell.homebrewFormulapowershellFormula used on macOS/Linux for the PowerShell extension.
advanced.powershell.wingetPackageIdMicrosoft.PowerShellPackage used on Windows for the PowerShell extension.
advanced.vscode.profileDirectoriesper-OS stable/insiders pathsUses %VAR% on Windows and $HOME elsewhere.
advanced.vscode.managedSettingKeys.gitPathgit.pathSetting written with the resolved Git path.
advanced.vscode.managedSettingKeys.pythonInterpreterpython.defaultInterpreterPathSetting written with the resolved interpreter.
advanced.vscode.managedSettingKeys.phpValidatorphp.validate.executablePathSetting written with the resolved PHP executable.
advanced.vscode.managedSettingKeys.powerShellAdditionalExePathspowershell.powerShellAdditionalExePathsSetting written with the resolved PowerShell executable.
advanced.vscode.extensionClistable: code, insiders: code-insidersCLI used to install extensions per profile. A profile is skipped when its CLI is not on PATH or a known install location.
advanced.vscode.extensionCliFallbackPathsper-OS stable/insiders pathsWell-known install locations checked on macOS/Linux when the CLI isn't on PATH.
advanced.vscode.mcpFileNamemcp.jsonFile written next to settings.json in each profile.
advanced.vscode.settingsazureFunctions.showProjectWarning: falseNon-devcontainer settings the setup owns.
advanced.devcontainers.dockerAccessFeaturesmap of 3 modesFeature refs selected by user.devcontainers.dockerAccess.
advanced.devcontainers.settingKeys.featuresdev.containers.defaultFeaturesKey holding the feature map.
advanced.devcontainers.settingKeys.extensionsdev.containers.defaultExtensionsKey holding the extension list.
advanced.devcontainers.snippet.filejsonc.jsonSnippet file written under snippets/.
advanced.devcontainers.snippet.nameDev container (Ubuntu base)Snippet entry name.
advanced.devcontainers.snippet.prefixdevcontainerText typed to expand the snippet.

Precedence

For VS Code settings, later wins:

  1. advanced.vscode.settings
  2. dev container keys, when user.install.devcontainerDefaults is true
  3. managed Python global package install guidance
  4. resolved git.path / python.defaultInterpreterPath
  5. user.vscode.settings

Command-line parameters override the config for a single run.

Extensions

user.vscode.extensions.install is a lean, broadly useful baseline rather than an exhaustive list: formatting and linting (editorconfig, prettier, eslint, ruff, markdownlint), Python (python, pylance, debugpy), GitHub (vscode-github-actions, vscode-pull-request-github), containers and remote (remote-containers, vscode-containers), plus powershell, yaml, makefile-tools, code-spell-checker, and markdown-all-in-one.

Stack-specific extensions are intentionally left out — Azure, Go, Swift, docs-authoring, and similar belong to individual workflows, not a shared baseline. Add whatever you need to the list.

user.vscode.extensions.block covers extensions that are deprecated or superseded by something in the install list, so having both causes duplicate diagnostics or fighting formatters:

BlockedSuperseded by
ms-python.autopep8, black-formatter, flake8, isort, pylintcharliermarsh.ruff
ms-azuretools.vscode-dockerms-azuretools.vscode-containers
ms-vscode.vscode-typescript-tslint-plugindbaeumer.vscode-eslint (TSLint is deprecated)
hookyqr.beautifyesbenp.prettier-vscode (unmaintained)
ms-vscode.powershell-previewms-vscode.powershell
eg2.vscode-npm-script, ms-vscode.node-debug2Built into VS Code

Blocked extensions are reported, not removed, unless uninstallBlocked is true. An extension listed in both install and block is a configuration error and fails the run.

Extension management needs the VS Code CLI (code) on PATH. Profiles whose CLI is missing are reported as [skip] and everything else still runs.

MCP servers

user.mcp.servers is merged into each profile's mcp.json. The shipped default is four servers that need no authentication and no local runtime beyond npx/uvx:

ServerTransportWhy it is a default
io.github.github/github-mcp-serverhttpRepos, issues, PRs. Useful in any repository.
microsoftdocs/mcphttpMicrosoft/Azure documentation lookup. No auth.
microsoft/markitdownstdio (uvx)Converts PDFs/Office docs to Markdown. Language-agnostic.
microsoft/playwright-mcpstdio (npx)Browser automation for front-end work.

Servers that are not shipped as defaults, and why:

Not includedReason
Azure, Azure DevOps, NuGet, TerraformRequire a subscription, an organization name, a token, or a .NET/Terraform stack. Useful, but not universal.
Enterprise and Sentinel endpointsTenant-entitled URLs. They fail for anyone without the entitlement.
Next.js devtools, awesome-copilotFramework-specific, or require a local Docker daemon.

Add any of these to user.mcp.servers yourself — the merge handles them the same way.

Existing entries are never overwritten. Only missing servers are added, so a locally pinned version or an added env block survives a re-run. Remove a server from mcp.json and it comes back on the next run; add it to user.mcp.block to stop that.

Never hardcode secrets. Use VS Code's ${input:id} placeholders with matching entries in user.mcp.inputs and mark secret prompts with "password": true. VS Code prompts for those values locally instead of storing them in this repository.

A server that references an ${input:id} with no matching definition fails the run, as does a server listed in both servers and block.

Settings deliberately excluded

user.vscode.settings holds portable editor, Git, terminal, and security preferences. Some categories are intentionally not shipped here:

ExcludedWhy
git.path, python.defaultInterpreterPath, php.validate.executablePath, powershell.powerShellAdditionalExePathsMachine-local; resolved and written by the installers. The PHP and PowerShell path settings are ignored by Settings Sync.
azureResourceGroups.selectedSubscriptions, @azure.argTenant, chat.mcp.serverSamplingContain tenant/subscription identifiers. Never commit these to a shared repo.
yaml.schemasAbsolute paths containing a username. Already in settingsSync.ignoredSettings.
terminal.integrated.cwdA personal folder convention.
chat.tools.global.autoApprove, chat.agent.sandbox.*, chat.agent.networkFilter, chat.tools.*.autoApproveAgent security posture. Auto-approving tool calls and disabling the sandbox is a personal risk decision and must not be a shared default. Set them yourself if you want them.
Other chat.* / github.copilot.* tuningFast-moving setting names and highly personal. Add to user.vscode.settings if you want them synced.

Anything in this list can still be added to user.vscode.settings on your own machine — the config is yours to extend.

Path placeholders

Config values may contain environment placeholders, expanded at read time:

FormPlatformExample
%VAR%Windows%APPDATA%\Code\User
$HOMEmacOS / Linux$HOME/.config/Code/User
{version}anyPython.Python.{version}
{wingetPackageId}any...\WinGet\Packages\{wingetPackageId}*\...

Shared code reference

src/config.ps1 (dot-source it)

NameKindPurpose
$DevSetupRootvariableRepository root, resolved from the file's own location.
$DevSetupConfigPathvariableDefault config path under config/.
Get-DevSetupConfig [-Path]functionLoad and parse the config; warns and returns empty if absent.
Get-DevSetupValue $cfg <dotted.key> [$default]functionSafe lookup. null and "" fall back to $default.
Expand-DevSetupPath <value>functionExpand %VAR% placeholders.
ConvertTo-DevSetupHashtable <object>functionPSCustomObject to hashtable for iteration.
Write-DevSetupStatus <state> <component> [detail]functionEmit one [found]/[install]/[skip]/[warn] line.
Get-DevSetupVSCodeProfilePath $cfg [-Platform]functionExisting settings.json paths for configured profiles.
Set-DevSetupVSCodeSetting $cfg <key> <value>functionWrite one setting to every profile, skipping no-ops.
Add-DevSetupUserPath <dir> [-Prepend]functionAdd a directory to the user PATH once, comparing whole entries.
Get-DevSetupGitCredentialSetting $cfgfunctionThe git config keys/values this setup owns on Windows.
Write-DevSetupGitIdentityStatus $cfg <git> [-Audit]functionIdentity reporting shared by audit and apply.
. (Join-Path$PSScriptRoot"..\config.ps1")
$config=Get-DevSetupConfig$version=Get-DevSetupValue$config"user.python.version""3.14"

src/config.sh (source it)

NameKindPurpose
DEVSETUP_ROOTvariableRepository root, resolved from the file's own location.
DEVSETUP_CONFIG_FILEvariableConfig path. Override by exporting it before sourcing.
DEVSETUP_READERvariableThe JSON reader (python3, python, or jq) resolved once at source time.
devsetup_config <dotted.key> [default]functionSafe lookup. Arrays print newline-separated.
devsetup_enabled <dotted.key> [default]functionTrue when the value is true.
devsetup_status <state> <component> [detail]functionEmit one status line.
devsetup_git_identity_status [audit]functionIdentity reporting shared by audit and apply.
devsetup_config_readerfunctionPrints DEVSETUP_READER; fails if none was found.
."$(dirname "$0")/../config.sh"
version="$(devsetup_config user.python.version 3.14)"

The config must be readable before Python is installed, so the reader is chosen from python3, python, then jq, and every lookup falls back to the caller-supplied default if none exist. Resolution happens at source time rather than per lookup: devsetup_config runs inside a $( ) subshell, so a value cached during a lookup would be discarded.

Individual scripts

Each installer runs standalone and accepts -Audit / --audit.

Git

.\src\scripts\install-portable-git.ps1 [-ConfigureVSCode] [-ForcePortable] [-Audit]
./src/scripts/install-portable-git.sh [--audit]
  • Windows downloads the latest Git for Windows portable build to the configured directory and adds it to the user PATH. An existing Git on PATH is detected and the download skipped unless user.git.forcePortable is true.
  • macOS reports and exits if Git and Xcode Command Line Tools are both missing; Apple offers no silent install path, so run xcode-select --install once yourself.
  • Linux uses an existing Git or Homebrew, otherwise installs Homebrew for Linux under $HOME (no root) and installs Git through it.
  • Configures the credential helper and applies user.git.userName / user.git.userEmail when set. Each value is compared first, so a second run reports [found].
  • -ConfigureVSCode points git.path at the resolved binary across every configured profile.

Python

.\src\scripts\install-python.ps1 [-ConfigureVSCode] [-PythonVersion<x.y>] [-Audit]
./src/scripts/install-python.sh [--print-path] [--audit]

Checks for a working interpreter first. On Windows it installs per-user via winget when available — winget packages go through a trusted pipeline and are not blocked by Defender Application Control / Exploit Guard ASR policies common on managed corporate devices, whereas executing a freshly downloaded uv.exe can be. If winget is unavailable, both platforms fall back to uv in a user-local location.

The version comes from user.python.version on every platform. The PowerShell script emits the resolved interpreter path as its final pipeline value; the shell script does the same under --print-path, with progress on stderr.

Node.js and npm

.\src\scripts\install-node.ps1 [-Audit]
./src/scripts/install-node.sh [--audit]

Windows installs Node.js LTS per-user through winget; macOS/Linux use Homebrew. If PowerShell execution policy blocks npm.ps1, use npm.cmd install / npm.cmd test — the same executable, without changing machine security policy.

PHP

./src/scripts/install-php.sh [--print-path] [--audit]

macOS/Linux use Homebrew and Windows uses WinGet to install PHP when it is missing. The resolved executable is written to VS Code's php.validate.executablePath, which restores built-in PHP validation. That absolute path is machine-local and explicitly excluded from Settings Sync.

PowerShell

.\src\scripts\install-powershell.ps1 [-Audit]
./src/scripts/install-powershell.sh [--print-path] [--audit]

macOS/Linux use Homebrew and Windows uses WinGet to install PowerShell 7 when it is missing. The resolved pwsh path is written to powershell.powerShellAdditionalExePaths, restoring discovery for the VS Code PowerShell extension. The path is machine-local and excluded from Settings Sync.

VS Code settings

python .\src\configure-vscode.py [--dry-run] [--config<path>] [--git-path<p>] [--python-path<p>] [--php-path<p>] [--powershell-path<p>]
python3 ./src/configure-vscode.py [--dry-run]

One cross-platform script, so the settings payload has a single definition. It writes two files per configured profile, both covered by Settings Sync:

  • settings.json — the merged settings described in Precedence.
  • snippets/jsonc.json — a devcontainer snippet. Type devcontainer in a new .devcontainer/devcontainer.json.
  • mcp.json — the configured MCP servers.

It then reconciles extensions through the VS Code CLI: installs anything missing from user.vscode.extensions.install, and reports (or removes) anything present from .block. See Extensions.

Finally it merges user.mcp.servers into each profile's mcp.json. See MCP servers. After writes finish, it validates the managed settings, snippet, extension list, and MCP entries by rereading the files and VS Code CLI output. If validation passes, user.vscode.settingsSync allows one final guarded sync request: the script checks VS Code's global user-data state for sync.enable=true and the configured account provider, then runs the configured VS Code CLI sync arguments. It skips sync when Settings Sync is off, the provider is not GitHub, or the CLI is absent.

The merge is additive and idempotent: existing settings and snippets are preserved, and JSONC comments and trailing commas are tolerated on read. The file is rewritten as plain JSON, so comments in settings.json are not preserved.

Settings Sync itself must still be enabled once from VS Code's Accounts menu — OAuth cannot be scripted. Binaries, PATH entries, credentials, and git identity stay machine-local and are never uploaded.

Repository hygiene

The repository is public and keeps only portable defaults in source control.

AreaCurrent posture
Community defaultsFunding, issue templates, and PR templates are inherited from the org-level .github repo.
Org automation config.github/bos-universal-config.json opts into common sync/lint settings only.
CODEOWNERS.github/CODEOWNERS requests security review for every PR.
IssuesEnabled for support and bug reports.
Projects and DiscussionsDisabled; this kit is small enough to keep planning in issues and PRs.
WikiDisabled; public docs live in README.md, SECURITY.md, and CONTRIBUTING.md.
Branch cleanupDelete branch on merge is enabled in GitHub repository settings.
SecretsNo credentials, tokens, tenant IDs, subscription IDs, or private endpoints belong in this repo.
WorkflowsNo action/release workflow is copied because this repo has no action.yml or package manifest.

Dev container defaults

Dev containers stay opt-in. Nothing here creates a .devcontainer folder or puts a workspace into a container; VS Code only containerizes a repo that already has a .devcontainer/devcontainer.json. These are the defaults applied if a container is built.

The default user.devcontainers.dockerAccess is outside-of-docker, which bind-mounts the host Docker socket. The container shares the host image cache (no double-pull) and needs no --privileged flag. Two consequences:

  • Paths in nested docker run -v calls resolve against the host filesystem, not the container's. Use ${localWorkspaceFolder} rather than $(pwd). This is the usual cause of confusing failures with act and nested Compose.
  • Socket access is root-equivalent on the host. Fine on a personal machine; not appropriate on shared or untrusted infrastructure.

Set dockerAccess to in-docker for true daemon isolation, accepting --privileged and a cold image cache, or none to add no Docker feature at all.

Troubleshooting

Set your git identity

Fill user.git.userName and user.git.userEmail in the config and the setup applies them. Use a GitHub noreply address if you do not want to expose a personal email address.

PATH changes are not visible

The scripts update the user-levelPATH, which existing shells do not inherit. Open a new terminal, or reload VS Code.

Docker Desktop re-prompts for file sharing on non-C: drives

If Docker Desktop shows a Filesharing dialog every time you run docker compose/docker run for a project on a drive other than C:, this is Docker Desktop/Windows behavior, not something VS Code or Settings Sync controls:

  • With the Hyper-V backend, Settings → Resources → File sharing pre-authorizes a directory once.
  • With the WSL 2 backend (the default), that persistent allow-list does not exist for drives WSL does not auto-mount, so Docker re-prompts per session by design. Updating Docker Desktop does not fix it.

Options: keep the project on C:, work inside the WSL distro's own filesystem and run Compose from within WSL, switch to the Hyper-V backend, or click Yes each session.

PowerShell blocks npm.ps1

Use npm.cmd instead of npm. Same executable, no security policy change.

License

Apache License 2.0 — see LICENSE and NOTICE.

About

Cross-platform, no-admin developer environment bootstrapper for Windows, macOS, and Linux. Installs Git, Node.js, and Python per-user, then applies VS Code settings, extensions, and MCP config from a single JSON source of truth. Idempotent, with an audit-only mode to preview changes before anything is installed.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages