6.5 KiB
status, created, spec
| status | created | spec |
|---|---|---|
| implemented | 2026-08-07 | ../../specs/platform/requirements/go-dev-launcher.md |
Plan: Go dev launcher and minimal Node surface
Current state
apps/backend/internal/launcher already implements everything dev needs except the
dev-specific pieces. Reusable as-is:
| Concern | Location |
|---|---|
Arg parsing, ParseError, port flags |
options.go |
Port selection, explicit-port preflight, canBind |
ports.go |
| Health probe with launcher token, foreign-process detection | health.go |
| Process supervision, groups, Ctrl-C, force-kill, ring-buffered output | process.go, process_group_{unix,windows}.go |
| Restart control socket + launch manifest | supervisor.go |
| Backend env assembly | env.go |
Startup banner, browser open, waitForAppExit |
start.go |
Two details matter for the design:
supervisor.go:169allowedSupervisorEnvalready allowlistsKANDEV_WEB_INTERNAL_URLandKANDEV_DEBUG_DEV_MODE. No change needed there.supervisor.go:41launchRestartableBackendcallsresolveHomeDir()internally, reading the launcher's own environment. Dev needs a repo-local home, so this must become an explicit parameter (task 05).
Gaps, all dev-only:
- No
devcommand, no--web-internal-port, noWebPortinportConfig. - No repo-root discovery,
.kandev-devhome, or task-workspace detection. - No production-DB backup.
- No Vite child launch or token-less URL readiness probe.
Approach
Port dev into the Go launcher in three waves: pure helpers first (independently
testable, no ordering constraints between them), then command wiring and orchestration,
then the Makefile cutover and the TypeScript deletion.
The deletion is deliberately last and in its own task. Until make dev is proven on the
Go path, apps/cli/src/** is the rollback.
Design decisions
Backend child stays make -C apps/backend dev. Re-execing self __backend (what
start does) would be simpler but would silently drop rebuild-on-restart, which is the
point of the restart button in dev. Keeping make preserves it.
make dev execs a copy of the binary. Because launcher and backend are one binary,
the child make rebuilds bin/kandev underneath the running launcher. On Linux/macOS
go build unlinks before writing so the running process survives; on Windows the delete
fails and the rebuild errors. Exec'ing bin/kandev-launcher (a copy made after build)
removes the hazard on every platform for one cp.
Vite readiness is a separate probe. waitForHealth requires the launcher health
token by design (PR #2394 made a token mismatch a hard failure). Vite emits no such
token, so it needs its own probe that accepts any HTTP response. Do not weaken
waitForHealth to accommodate it.
Dependency order
wave 1 task-01 dev paths task-02 db backup task-03 web child
│ │ │
wave 2 └────────┬──────────────┴──────────────────────┘
├── task-04 dev command wiring
└── task-05 runDev orchestration (depends on 01–04)
│
wave 3 ┌─────────────────────┼─────────────────────┐
task-06 Makefile task-07 delete TS task-08 docs
(depends on 06)
Wave 1 tasks touch disjoint new files and are parallel-safe. Wave 3's task-07 must follow
task-06, because deleting apps/cli/src before the Makefile switches would break
make dev outright.
Tasks
| ID | Title | Wave | Status |
|---|---|---|---|
| 01 | Dev paths, repo root, and dev backend env | 1 | done |
| 02 | Production database backup in Go | 1 | done |
| 03 | Vite dev-server child and URL readiness | 1 | done |
| 04 | dev command, web port, and dev env wiring |
2 | done |
| 05 | runDev orchestration |
2 | done |
| 06 | Makefile cutover to the Go dev launcher | 3 | done |
| 07 | Delete apps/cli/src and drop CLI devDependencies |
3 | done |
| 08 | Documentation and guidance updates | 3 | done |
Likely files
New under apps/backend/internal/launcher/:
devpaths.go, devpaths_test.go, backup.go, backup_test.go, webchild.go,
webchild_test.go, dev.go, dev_test.go.
Modified: options.go, options_test.go, ports.go, ports_test.go, env.go,
env_test.go, supervisor.go, supervisor_test.go, launcher.go, cli/help.go,
constants.go.
Root: Makefile, apps/backend/Makefile, apps/cli/package.json,
apps/cli/bin/native-shim.test.mjs, apps/package.json,
.github/workflows/frontend-tests.yml, CLAUDE.md,
docs/remote-cloud-environment.md.
Deleted: apps/cli/src/**, apps/cli/tsconfig.json, apps/cli/vitest.config.ts.
Risks
- Windows dev has no CI coverage.
make test-windowsruns a unit subset, not a realmake dev. The winjob removal and thecmd.exe /c pnpmshim need manual verification on Windows before merge, or the winjob line inmake devshould stay until someone can test. Call this out in the PR. pnpm -r exec tscbreaks onceapps/cli/tsconfig.jsonis gone (Makefile:650). Task 07 must convertmake typecheckto explicit--filterarguments.knipdead-code detection may flag the trimmedapps/clidifferently. Runpnpm run dead-codeas part of task 07.- Release flow reads
apps/cli/package.jsonin three places (release.yml:224,251,381,publish-npm.sh:134,259). Task 07 must not touchname,version,bin,files, oroptionalDependencies. .kandev-devvs. inheritedKANDEV_HOME_DIR. The launcher's ownresolveHomeDir()reads the ambient env; inside a Kandev task workspace that env is the parent backend's. Task 05's explicit-homeDir refactor is what prevents the dev supervisor directory from landing in the parent's home.
Verification
Per-task commands are in the task files. Before opening the PR:
make -C apps/backend test
make -C apps/backend lint
cd apps && pnpm --filter kandev test
Manual, on the branch, since no automated test covers the real launch:
make dev # backend + Vite come up, browser opens, Ctrl-C leaves nothing
make dev PORT=38500 WEB_PORT=37500
make dev-prod-db # verify a dev-prod-db-*.db lands in ~/.kandev/data/backups/
Confirm no stray processes after Ctrl-C:
pgrep -af 'kandev|vite' || echo clean