Feature: One-Command DCT Update
IMPLEMENTATION RULES: Before implementing this plan, read and follow:
- WORKFLOW.md - The implementation process
- PLANS.md - Plan structure and best practices
Status: ✅ Completed (2026-04-07, macOS tested. Windows testing: see PLAN-windows-testing.md)
Goal: Make updating DCT a single dev-update command + one click, and remove the legacy dev-sync mechanism.
Last Updated: 2026-04-06
Investigation: INVESTIGATE-one-command-update.md — all research and testing completed
Priority: High — current update flow requires Docker knowledge most developers don't have
Overview
Currently updating DCT requires 3 manual steps involving Docker commands and VS Code Command Palette. With docker-outside-of-docker now available inside the container, dev-update can pull the new image and trigger VS Code's rebuild prompt automatically.
Also removes dev-sync (script-only updates) — a legacy workaround from before Docker was available inside the container. One version, one command.
Before: dev-update → shows instructions → user runs docker pull → user opens Command Palette → user clicks Rebuild (3 steps)
After: dev-update → automatic pull → VS Code prompts Rebuild → user clicks yes (1 command + 1 click)
Phase 1: Add DCT_IMAGE_VERSION to user template — ✅ DONE
Tasks
- 1.1 Add
"DCT_IMAGE_VERSION": "1.7.17"toremoteEnvindevcontainer-user-template.json - 1.2 DCT dev devcontainer doesn't use
remoteEnv(uses lifecycle commands) — skipped, not applicable - 1.3
install.shdownloads the template as-is, soDCT_IMAGE_VERSIONis included automatically
Validation
New installs via install.sh have DCT_IMAGE_VERSION in their devcontainer.json.
Phase 2: Rewrite dev-update to pull + trigger rebuild — ✅ DONE
Tasks
- 2.1 Check if Docker CLI is available (
command -v docker). Falls back to manual instructions. - 2.2
docker pull ghcr.io/helpers-no/devcontainer-toolbox:latestwith progress output. - 2.3 Update
DCT_IMAGE_VERSIONin devcontainer.json viased. - 2.4 Completion message telling user to click Rebuild.
- 2.5 Handle pinned image tags: detect non-
:latesttag, show instructions instead of pulling. - 2.6 Edge cases: no update, pull failure, missing field, all handled.
- 2.7
--checkflag for version check without pulling.
Validation
Pending E2E test in Phase 5.
Phase 3: Remove dev-sync — ✅ DONE
Tasks
Note (discovered 2026-04-06): dev-sync running on startup causes a false VS Code rebuild prompt ("Configuration changed") on every fresh container start. This trains users to click "Ignore" — exactly the opposite of what we need when dev-update triggers a real rebuild prompt. Removing dev-sync is critical for the update UX.
- 3.1 Replace auto-sync in
image/entrypoint.shwith lightweight version check + notification - 3.2 Deleted
dev-sync.shfrom.devcontainer/manage/ - 3.3 Remove
dev-syncsymlink fromimage/Dockerfile - 3.4 Deleted
scripts-version.txtfrom repo + removed COPY fromimage/Dockerfile - 3.5 Removed
scripts-version.txtgeneration frombuild-image.ymlandzip_dev_setup.yml, simplified zip + commit steps - 3.6 Rewrote
lib/version-utils.sh— removed all scripts version tracking, single version system - 3.7
dev-helpauto-generates from script metadata — removingdev-sync.shremoves it automatically - 3.8 Rewrote
releasing.mdfor single version system, updatedconfiguration.mdstartup flow
Validation
Container starts without sync attempt. dev-sync command no longer exists. Startup is faster (no 10s sync check). dev-update is the only update command.
Phase 4: Startup notification — ✅ DONE
Tasks
- 4.1 In entrypoint.sh, check remote version via
curlwith 5s timeout - 4.2 If newer version exists, show in startup log:
⚠️ DCT update available: v1.7.17 → v1.7.18
Run: dev-update - 4.3 Cache the check result for 24 hours — deferred, the 5s timeout is sufficient for now
Validation
Start a container with an older image version. Welcome message shows update notification. Running dev-update pulls and triggers rebuild.
Phase 5: E2E testing — ✅ DONE (2026-04-06)
Tasks
- 5.1 Tester's devcontainer.json set to
:latestwithDCT_IMAGE_VERSION: 1.7.19 - 5.2 Full flow tested: v1.7.19 → v1.7.20. Startup showed "Update available",
dev-updatepulled, VS Code prompted Rebuild. - 5.3 No-update case — not explicitly tested (low risk, simple version comparison)
- 5.4 Docker unavailable fallback — not explicitly tested (code path is clear)
- 5.5 Startup notification confirmed working with outdated image
- 5.6 No false rebuild prompt on clean container start (earlier false prompt was from manual test file edits)
Validation
Full update cycle works end-to-end. One command + one click.
Phase 6: Template replacement on every update — ✅ DONE
Problem: dev-update only changed DCT_IMAGE_VERSION but didn't update the rest of devcontainer.json. When we add new fields to the template (e.g., DEV_HOST_* env vars, new features), existing users didn't get them.
Solution: DCT owns devcontainer.json. On every dev-update, download the latest template from GitHub, back up the old file, replace entirely. CI already sets DCT_IMAGE_VERSION in the template, so no sed needed.
Tasks
- 6.1 Added
"managed"message tocustomizations.devcontainer-toolboxin template (v1.7.21) - 6.2
dev-updatedownloads latestdevcontainer-user-template.jsonafter pulling image - 6.3 Back up current devcontainer.json to
.devcontainer/backup/devcontainer.json.<old-version> - 6.4 Replace devcontainer.json with downloaded template (CI already has correct
DCT_IMAGE_VERSION) -
6.5 Set DCT_IMAGE_VERSION via sed— not needed, CI handles it in the template - 6.6 VS Code detects the change → rebuild prompt (already works)
- 6.7
.devcontainer/backup/added to.gitignoreviaensure-gitignore.sh(with CI permission fix) - 6.8 Tested: tester's old template →
dev-update→ new env vars appeared, backup created
Validation
dev-update replaces devcontainer.json entirely. Old file backed up. New template fields (env vars, features, extensions) appear without user action.
Acceptance Criteria
-
dev-updateautomatically pulls new image (no manualdocker pull) - VS Code prompts rebuild after
dev-updatecompletes (viaDCT_IMAGE_VERSIONin remoteEnv) -
dev-synccommand removed -
scripts-version.txtremoved — single version inversion.txt - Startup shows notification when image is outdated
- Graceful fallback when Docker CLI not available (code path exists)
-
dev-update --checkstill works (version check without pulling) -
devcontainer-user-template.jsonincludesDCT_IMAGE_VERSION - CI auto-updates
DCT_IMAGE_VERSIONon each image build -
dev-updatereplaces devcontainer.json with latest template on every update (Phase 6) - Old devcontainer.json backed up to
.devcontainer/backup/(Phase 6) - Template includes "managed by dev-update, do not edit" message (Phase 6)
Files Changed
Modified:
.devcontainer/manage/dev-update.sh— rewritten: docker pull + sed DCT_IMAGE_VERSION + rebuild prompt.devcontainer/manage/lib/version-utils.sh— removed scripts version tracking, single version systemdevcontainer-user-template.json— addedDCT_IMAGE_VERSIONto remoteEnvimage/entrypoint.sh— replaced dev-sync with version check notificationimage/Dockerfile— removed dev-sync symlink + scripts-version.txt COPY.github/workflows/build-image.yml— removed scripts-version.txt generation.github/workflows/zip_dev_setup.yml— removed scripts-version.txt from zip + commitwebsite/docs/contributors/releasing.md— rewritten for single version systemwebsite/docs/configuration.md— updated startup flow
Created:
website/docs/contributors/architecture/devcontainer-json.md— full field referencewebsite/docs/ai-developer/plans/backlog/INVESTIGATE-one-command-update.md— investigationwebsite/docs/ai-developer/plans/active/PLAN-one-command-update.md— this plan
Deleted:
.devcontainer/manage/dev-sync.sh— legacy script update mechanismscripts-version.txt— legacy scripts version tracking