Plan: dct-init — One Command to Set Up Any Project Folder
IMPLEMENTATION RULES: Before implementing this plan, read and follow:
- WORKFLOW.md - The implementation process
- PLANS.md - Plan structure and best practices
Status: Active
Goal: After the first install, a user sets up any new project folder by typing dct-init in it, on every machine: Windows or Mac, managed or unmanaged.
Priority: High — today the experience depends on how the PC was set up.
Last Updated: 2026-09-25
Related: PLAN-fix-windows-quickstart, PLAN-host-installer-handover, helpers-no/client-provisioning
Problem
| Installed by | Puts on the PC | Set up a new folder with |
|---|---|---|
| client-provisioning (Intune/Jamf, managed PCs) | devcontainer-init (Windows: Program Files, on PATH; Mac too) | devcontainer-init |
DCT irm … | iex (Windows, any PC) | nothing, only files in the current folder | the whole irm line again |
DCT curl … | bash (Mac/Linux) | dct-exec, dct-find-container (run commands in a container) | the whole curl line again |
client-provisioning's devcontainer-init also does less than DCT's installer: it downloads DCT's template from main unpinned, does not check that Rancher Desktop is running, and does not install the Dev Containers extension.
Decision (Terje, 2026-09-25)
- DCT installs the command itself, per user and without admin, as part of its installer. Nobody uses
devcontainer-inittoday, so the name is free to choose. - Name:
dct-init, alongsidedct-execanddct-find-container(confirmed by Terje, 2026-09-25). - Rule (Terje, 2026-09-25): every
dct-*command is installed by DCT's own install script, the one that downloadsdevcontainer.json(install.ps1/install.sh), on every platform. Not by client-provisioning, and not by anything else. Todayinstall.shinstallsdct-execanddct-find-containeron Mac/Linux, andinstall.ps1installs none, so Windows needs PowerShell versions of both (Phase 2b). - DCT owns
devcontainer.json(contract with client-provisioning, urb-agents #1505), so client-provisioning'sdevcontainer-initis retired, or becomes a call todct-init. That change is theirs to make.
Design
dct-initholds the install logic. Everythinginstall.ps1/install.shdoes today for a folder moves into it:- check Rancher Desktop is installed, visible and running
- refuse system folders (PLAN-fix-windows-quickstart task 2.7)
- back up an existing
.devcontainer/, refusing when a backup already exists - write
devcontainer.json - write
.vscode/extensions.json - install the extension
- pull the image
- print plain messages
install.ps1/install.shbecome a small bootstrap. They installdct-initfor the user, then run it once in the current folder. The Quick Start command stays the same.- Where it lives (no admin):
- Windows:
%LOCALAPPDATA%\devcontainer-toolbox\bin\withdct-init.ps1and adct-init.cmdshim, added to the user PATH. - Mac/Linux:
~/.local/bin/dct-init, next todct-exec.
- Windows:
- Exit codes become possible. A script file (unlike
irm | iex) can exit without closing the user's window, sodct-initimplements the contract's codes:0done,1prerequisite missing,2download/network,3target folder, withERRnnnon the error line. client-provisioning callsdct-init -TargetDir <path>instead of fetchinginstall.ps1. - Updating: running the Quick Start line again replaces
dct-init. Whetherdct-initshould update itself is out of scope for the first version.
Risk to verify first: PowerShell execution policy
irm | iex is not subject to the execution policy, but a .ps1 file is. The Windows client default (Restricted) blocks it. The .cmd shim can run powershell -NoProfile -ExecutionPolicy Bypass -File dct-init.ps1, but a policy enforced through Intune/Group Policy (for example AllSigned) overrides Bypass, and then an unsigned dct-init.ps1 does not run. That would break dct-init exactly on managed PCs.
Phase 1 checks this on Terje's managed PC before anything is built. If the policy blocks it, the options are code-signing the script (needs a certificate the PC trusts: an organisation decision) or keeping dct-init inside a signed or allowed wrapper.
Phase 1: Check execution policy on a managed PC — ✅ DONE
Tasks
- 1.1 On Terje's managed PC, record
Get-ExecutionPolicy -List. - 1.2 Create a one-line test
.ps1plus.cmdshim in the user's profile, the same waydct-initwould be installed, and check it runs from a new PowerShell window by typing its name. - 1.3 Decide with Terje: go ahead unsigned, sign it, or change the design.
Result (Terje's managed PC, urb-agents #1541, 2026-09-25): the real dct-init install from the branch ran without ERR006, so neither MachinePolicy nor UserPolicy enforces AllSigned or Restricted. dct-init.cmd then ran dct-init.ps1 from %LOCALAPPDATA% by name in a new window. Decision: go ahead unsigned. (#1539's dummy-script test was superseded by this real one; the Get-ExecutionPolicy -List table itself was not pasted.)
Validation
A written result in this plan: the policy values and whether the shim ran.
Phase 2: dct-init for Windows and Mac/Linux — ✅ DONE
Tasks
- 2.1 Move the per-folder logic from
install.ps1/install.shintodct-init, keeping every message and check that works today. - 2.2 Parameters:
-TargetDir/--target-dir(default: current folder); no prompts; never elevates; safe to run twice. - 2.3 Exit codes and
ERRnnnlines as in the contract. - 2.4
install.ps1/install.sh: installdct-initper user (plus PATH), then run it in the current folder. Tell the user in one sentence that next time they can just typedct-initin a new folder (in a new window).
As built (2026-09-25):
- Files:
host-tools/dct-init.sh(installed as~/.local/bin/dct-init)host-tools/dct-init.ps1+host-tools/dct-init.cmd(installed to%LOCALAPPDATA%\devcontainer-toolbox\bin, which is added to the user PATH)
- The bootstraps:
install.sh/install.ps1are now bootstraps that install the commands and rundct-initonce.install.shinstalls all threedct-*commands;install.ps1onlydct-inituntil Phase 2b. - Checks
dct-initdoes:- Rancher Desktop installed, visible and running
- VS Code (checked up front)
- Intel Mac (
ERR005) - system folders, the drive root and the home folder (
ERR011; fix-plan task 2.7) - an existing backup is never overwritten (
ERR012; fix-plan task 2.4) - a note when run as administrator
- Exit codes 0/1/2/3 with
ERRnnn, per the contract. - Execution policy:
install.ps1stops withERR006when Group Policy/Intune enforcesAllSignedorRestricted;-ExecutionPolicy Bypassin the.cmdshim does not override an enforced policy, and the installer does not try to work around one. - For tests:
DCT_INSTALL_SOURCEinstalls from a checkout instead of GitHub. - Verified locally:
- bash, via
install.shwith a throwaway HOME and stubdocker/code: every case returns the contract's exit code (not running 1, pull fails 2, system folder / missing folder / home / backup exists 3, success 0), andinstall.shpasses it on;dct-initworks by name in a new folder. - PowerShell 7 on Linux,
install.ps1run viaInvoke-Expressionlike the Quick Start: not running / success / rerun-with-backup / backup-exists (3), with the session kept alive and$ErrorActionPreferenceuntouched. - Lint: shellcheck, PSScriptAnalyzer (0 findings apart from
PSAvoidUsingWriteHost), actionlint;.ps1files are plain ASCII (Windows PowerShell 5.1 reads BOM-less files as ANSI).
- bash, via
- Verified on Windows: the
Host Commandsjobs on PR #105 (9/9 checks onwindows-latest, Linux green), then Terje's managed PC (urb-agents #1541): the first install,dct-initby name in a new window (exit 0), and Rancher stopped (ERR003, exit 1, nothing written). - Fixed after the PC test:
dct-init -TargetDir C:\Windows\System32with Rancher stopped reportedERR003(1) instead ofERR011(3), because prerequisites were checked before the folder, which cost the user two round trips. The folder is now checked first (both scripts), with a regression check in both CI jobs.
Validation
Stub-docker tests like 1.8.3's, for dct-init itself: each failure case returns its exit code and writes nothing. Plus a CI job on windows-latest that installs dct-init and runs it by name from a fresh shell.
Phase 2b: dct-exec and dct-find-container for Windows
The rule above requires them on Windows too; today they are bash-only (their plan, PLAN-dct-exec-host-helper, left Windows out of v1).
Tasks
- 2b.1 Port both to PowerShell (
dct-exec.ps1,dct-find-container.ps1, each with a.cmdshim), installed byinstall.ps1in the same user folder asdct-init. - 2b.2 Check how the
devcontainer.local_folderlabel looks for a Windows project path (drive letter, backslashes), which the bash version never had to handle. Verify on Terje's PC against a running container. - 2b.3 Interactive (
dct-exec bash) and piped (echo hi | dct-exec cat) cases, as in the bash version.
Validation
On Terje's PC, in a project folder with a running devcontainer: dct-find-container prints its name and dct-exec bash opens a shell in it.
Phase 3: Docs, client-provisioning, release — IN PROGRESS
Tasks
- 3.1 Quick Start and Getting Started: "next time, type
dct-initin a new project folder".- Done 2026-09-25: a new Getting Started section "Setting Up Another Project:
dct-init" (what it checks, where it lives,-TargetDir, exit codes for scripts); a "Next time" line in the Quick Start ofindex.mdandREADME.md; the migration steps and thedct-execsection updated. Terje chose to merge the code and the docs together, so the site mentionsdct-initat the same moment new installs get it.
- Done 2026-09-25: a new Getting Started section "Setting Up Another Project:
- 3.2 Tell client-provisioning (bus):
dct-init -TargetDiris the call, and theirdevcontainer-initcan go.- Sent as urb-agents #1543 (2026-09-25), with the exit codes and the
ERRnnnlist. They accepted it. They retiredevcontainer-initonly after DCT's first pinned release, and then with Terje's go. Their question led to 1.9.1:dct-initnow findsdockerin Rancher Desktop's own folder when PATH is stale (PR #106).
- Sent as urb-agents #1543 (2026-09-25), with the exit codes and the
- 3.3 Test on Terje's PC: first install via the Quick Start, then
dct-initin a second, new folder. - 3.4 Release: bump
version.txt(1.9.0, MINOR: a new feature).
Validation
On Terje's PC a second folder is set up with dct-init alone and opens in its container.
Acceptance Criteria
- After the Quick Start,
dct-initworks by name in a new window on Windows and Mac - Every
dct-*command is installed byinstall.ps1/install.sh, on Windows as well as Mac/Linux - It never needs admin, and it returns the contract's exit codes
- client-provisioning calls
dct-initand ships no copy of its own - Execution policy on managed PCs is checked, and handled
Files to Modify
install.ps1,install.sh(become bootstraps)- new
dct-init.ps1,dct-init.cmd,dct-init(bash) - new
dct-exec.ps1,dct-find-container.ps1and their.cmdshims (inhost-tools/) .github/workflows/host-commands.yml(dct-init job), testswebsite/docs/getting-started.md,website/docs/index.md,README.mdversion.txt