Skip to content

Onboarding Bootstrap & lantern CLI โ€” Design Spec โ€‹

Date: 2026-06-12 Status: Implemented 2026-07-13 on claude/repo-memory-skills-org-p0owiz (postinstall banner, .vscode folderOpen task, lantern bin with doctor/setup/onboard/dev/help, devcontainer pointer, guide updates). Adds onboard beyond the original table to wire the newer .agents/context/ layer. Closes #595. Companion guides: docs/engineering/guides/ONBOARDING.md, docs/engineering/guides/ENVIRONMENT_SETUP.mdTarget branch: dev

1. Problem โ€‹

When a developer clones the repo for the first time, there is no reliable moment where the repo can greet them and steer onboarding โ€” unless they happen to be in a Codespace.

A bare git clone followed by opening a terminal triggers nothing from the repo:

  • Git deliberately does not run repo-shipped hooks on clone (that would be remote code execution on clone).
  • .bashrc / .zshrc belong to the developer's machine, not the repo.
  • Opening a terminal runs the developer's shell init, not ours.

What we have today only covers part of the surface:

Entry pointFires whenStatus
devcontainer postAttachCommandevery editor attach in Codespaces / Dev Containersโœ… prints ๐Ÿฎ banner โ€” .devcontainer/devcontainer.json
devcontainer postCreateCommandcontainer first buildโœ… installs Node + deps
husky preparenpm installโœ… wires git hooks only โ€” no onboarding output
npm postinstallfirst npm install (everyone)โŒ gap
VS Code folderOpen taskopening folder locally (non-container)โŒ no .vscode/tasks.json

The uncovered persona is the plain local-clone developer: clones the repo, opens VS Code locally (no container), runs npm install, and gets no guidance toward npm run env:bootstrap, prerequisite checks, or the help index. Onboarding correctness is currently tribal knowledge spread across two guide docs.

A secondary problem: we have the substance of a CLI (npm run help reading scripts-info, env:bootstrap/env:check/env:sync, the Lantern Control VS Code panel) but no single discoverable entrypoint or health-check command. "Is my setup correct?" has no one-command answer.

2. Goal โ€‹

  1. Give every fresh clone โ€” local or Codespace โ€” a single, idempotent onboarding nudge that points at the right next command.
  2. Provide lantern doctor: one command that verifies a developer's environment (Node vs .nvmrc, gcloud auth, .env.local completeness, optional tooling) and prints actionable next steps.
  3. Expose a thin local lantern bin that dispatches to existing scripts โ€” no logic duplication, no published package.

Out of scope: a published @lantern/cli npm package (overkill for an internal monorepo โ€” adds versioning/publishing overhead for team-only tooling); rewriting bootstrap-env.mjs / sync-env.mjs (the CLI wraps them); changing the Codespace flow, which already works.

3. Approach โ€‹

Three additive pieces, ordered by leverage. None removes or changes existing behavior.

3.1 postinstall onboarding banner โ€‹

Add a postinstall script that prints a short, idempotent banner after npm install โ€” the one moment every fresh clone hits exactly once.

jsonc
// package.json
"scripts": {
  "postinstall": "node tooling/scripts/postinstall-banner.mjs"
}

tooling/scripts/postinstall-banner.mjs (new):

  • CI guard: no-op when process.env.CI is set (keeps CI logs clean, avoids noise in automation).
  • Idempotent + cheap: postinstall runs on every install, so the script must be a fast console.log, never heavy work. No network, no file writes.
  • Quiet on repeat (optional): skip the banner if .env.local already exists and is complete (i.e. the dev is past onboarding), so established devs aren't nagged on every npm install.
  • Content: points at npx lantern doctor, npm run env:bootstrap, and npm run help.

This closes the row marked โŒ gap in ยง1 and is the single highest-coverage change โ€” npm install is unavoidable on a fresh clone.

3.2 .vscode/tasks.json folder-open task โ€‹

A runOptions.runOn: "folderOpen" task that prints the same banner. Covers the VS Code-local developer before they run npm install, so they see guidance the moment they open the folder.

jsonc
// .vscode/tasks.json (new)
{
  "version": "2.0.0",
  "tasks": [{
    "label": "Lantern: onboarding hint",
    "type": "shell",
    "command": "node tooling/scripts/postinstall-banner.mjs --folder-open",
    "presentation": { "reveal": "silent", "panel": "shared" },
    "runOptions": { "runOn": "folderOpen" }
  }]
}

Reuses the same script (a --folder-open flag adjusts copy: "run npm install first"). Note VS Code prompts the user to allow folder-open auto-tasks the first time โ€” this is expected and acceptable.

3.3 Thin lantern bin โ€‹

Add a bin field so lantern <cmd> is on PATH inside the repo after install:

jsonc
// package.json
"bin": { "lantern": "tooling/scripts/lantern.mjs" }

tooling/scripts/lantern.mjs (new) is a dispatcher, not a reimplementation. Subcommands shell out to existing scripts:

SubcommandDelegates toPurpose
lantern doctornew check logic (ยง4) + sync-env.mjs --checkenvironment health check
lantern setupbootstrap-env.mjspull secrets from Secret Manager
lantern devnpm run devstart web preview
lantern helphelp.mjsgrouped script index
lantern (no arg)prints doctor summary + help pointerdefault landing

doctor is the centerpiece โ€” it turns "is my setup right?" into one command and is the natural thing for the banner (ยง3.1) and the Codespace postAttachCommand to point at.

4. lantern doctor checks โ€‹

Each check is non-fatal and prints a โœ… / โš ๏ธ / โŒ line plus a fix hint. Exit code is non-zero only if a required check fails, so it's usable in scripts.

CheckHowSeverity if failing
Node versioncompare process.version against .nvmrc (24.16.0) and engines.node (>=24.0.0)required
Dependencies installednode_modules present + lockfile in syncrequired
gcloud CLIgcloud version (mirrors bootstrap-env.mjs:181)optional โ€” only needed for secret pull
gcloud ADCgcloud auth application-default print-access-tokenoptional
.env.local completenessreuse sync-env.mjs --check (npm run env:check)warning
firebase-toolsfirebase --version (emulators / rules)optional
git hooks installed.husky/_ present (husky prepare ran)warning

doctor reuses the prerequisite logic already in bootstrap-env.mjs rather than duplicating it โ€” extract checkGcloud()-style helpers into a shared module if needed, or call npm run env:check as a child process. No new secret-fetching logic.

5. Wiring existing entrypoints to the new CLI โ€‹

  • devcontainer postAttachCommand (.devcontainer/devcontainer.json): append a pointer to npx lantern doctor after the existing ๐Ÿฎ banner. The auth/bootstrap instructions stay as-is.
  • ONBOARDING.md / ENVIRONMENT_SETUP.md: replace the hand-listed setup steps with npx lantern doctor โ†’ npx lantern setup as the canonical path, keeping the manual steps as a fallback section.
  • Lantern Control VS Code panel (shares tooling/shared/script-groups.cjs): optionally surface a "Doctor" button later โ€” not required for v1.

6. Why not the alternatives โ€‹

  • direnv .envrc โ€” auto-runs on cd, but requires every dev to install direnv and run direnv allow. Higher friction than the install hook for strictly worse coverage. Rejected.
  • Git hook injected via husky โ€” prepare runs on install and could print a banner, but conflates "wire hooks" with "onboard human"; hooks shouldn't be a UI surface. The dedicated postinstall is clearer. Rejected for the banner; husky keeps its existing job.
  • Published @lantern/cli package โ€” versioning, publishing, and a release cadence for tooling only this team uses. A repo-local bin gets the discoverability (npx lantern) with none of the overhead. Rejected for now; revisit only if tooling is shared across repos.
  • Shell-rc injection โ€” invasive, modifies the developer's machine, hard to uninstall. Never. Rejected.

7. Risks & mitigations โ€‹

  • postinstall noise / CI breakage โ€” guarded by if (process.env.CI) return and kept to a pure console.log. No writes, no network, fast.
  • Repeat-nag fatigue โ€” banner self-suppresses once .env.local is complete (ยง3.1).
  • folderOpen task trust prompt โ€” VS Code asks to allow the auto-task once; documented in the onboarding guide so it's expected, not alarming.
  • CLI drifts from npm scripts โ€” lantern delegates to the same scripts help.mjs/package.json expose, so there's one source of truth. doctor reuses bootstrap-env.mjs prerequisite checks rather than forking them.

8. Implementation checklist โ€‹

  1. tooling/scripts/postinstall-banner.mjs (+ CI guard, --folder-open flag, completeness self-suppress).
  2. package.json: add postinstall script + bin field.
  3. tooling/scripts/lantern.mjs dispatcher with doctor / setup / dev / help.
  4. lantern doctor checks (ยง4), reusing bootstrap-env.mjs prerequisite helpers + env:check.
  5. .vscode/tasks.json folder-open task.
  6. Append npx lantern doctor pointer to postAttachCommand.
  7. Update ONBOARDING.md + ENVIRONMENT_SETUP.md to lead with the CLI.
  8. Add scripts-info entries so the new scripts show in npm run help.

9. Rollout โ€‹

Single PR to dev. No migration, no data changes, no prod surface โ€” purely developer tooling. Verify by: fresh npm install (banner prints, CI run stays quiet), npx lantern doctor against both a complete and an incomplete .env.local, and a Codespace rebuild to confirm the postAttachCommand pointer renders.

Built with VitePress