14 KiB
BeadBoard Global Install Runtime Manager Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Replace repo-path shim install behavior with a robust global install model where beadboard runs from managed runtime home and works from any directory.
Architecture: Keep a hybrid install strategy with npm-global as primary and script bootstrap as fallback, but unify both paths behind one runtime manager contract (~/.beadboard/runtime/<version> + stable shims). Preserve backward compatibility by detecting legacy repo-bound shims and offering migration. Implement with strict TDD and explicit installer smoke tests.
Tech Stack: Node.js (ESM), TypeScript/tsx for CLI code, PowerShell + POSIX shell wrappers, GitHub Actions, Node test runner.
Pre-Implementation Checklist
Task 0: Baseline and Safety Snapshot
Files:
- Modify:
beadboard/.beads/issues.jsonlviabdcommands only - Read:
beadboard/AGENTS.md - Read:
beadboard/NEXT_SESSION_PROMPT.md
Step 1: Claim/track implementation bead(s)
Run:
cd beadboard
bd create --title="Global installer runtime manager implementation" --description="Implement npm-global-first runtime manager with migration from repo-path shims" --type=task --priority=1 --label="installation,cli,runtime"
bd update <new-bead-id> --status in_progress --assignee <agent-bead-id>
Step 2: Capture baseline gate status
Run:
npm run typecheck
npm run lint
npm run test
Expected: existing known unrelated failures may appear; record exact failing files/tests in bead notes.
Step 3: Commit checkpoint
No code changes yet. Do not commit.
Phase 1: Define Runtime Manager Contract
Task 1: Add runtime manager ADR and package contract
Files:
- Create:
docs/adr/2026-03-03-runtime-manager-global-install.md - Modify:
docs/adr/2026-03-03-global-installer-contract-and-manifest.md
Step 1: Write failing docs contract test
Create:
tests/docs/runtime-manager-adr-contract.test.ts
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import path from 'node:path';
test('runtime manager ADR exists and declares runtime home strategy', async () => {
const raw = await fs.readFile(path.resolve('docs/adr/2026-03-03-runtime-manager-global-install.md'), 'utf8');
assert.match(raw, /~\/\.beadboard\/runtime/i);
assert.match(raw, /npm i -g beadboard/i);
assert.match(raw, /legacy repo-bound shim migration/i);
});
Step 2: Run test to verify it fails
Run:
node --import tsx --test tests/docs/runtime-manager-adr-contract.test.ts
Expected: FAIL (ENOENT for missing ADR file).
Step 3: Write minimal implementation
Add ADR with:
- runtime directory layout
- shim strategy
- update/uninstall model
- compatibility migration model
- failure modes and rollback
Step 4: Run test to verify it passes
Run:
node --import tsx --test tests/docs/runtime-manager-adr-contract.test.ts
Expected: PASS.
Step 5: Commit
git add tests/docs/runtime-manager-adr-contract.test.ts docs/adr/2026-03-03-runtime-manager-global-install.md docs/adr/2026-03-03-global-installer-contract-and-manifest.md
git commit -m "docs: define runtime manager global install contract"
Phase 2: Implement Runtime Manager Library
Task 2: Add runtime manager core module with strict validation
Files:
- Create:
src/lib/runtime-manager.ts - Create:
tests/lib/runtime-manager.test.ts
Step 1: Write failing test
import test from 'node:test';
import assert from 'node:assert/strict';
import { getRuntimePaths, normalizeVersion } from '../../src/lib/runtime-manager';
test('normalizeVersion supports semver and rejects empty', () => {
assert.equal(normalizeVersion('1.2.3'), '1.2.3');
assert.throws(() => normalizeVersion(''));
});
test('getRuntimePaths builds ~/.beadboard/runtime/<version> layout', () => {
const p = getRuntimePaths('/tmp/home', '1.2.3');
assert.match(p.runtimeRoot, /runtime\/1\.2\.3$/);
assert.match(p.shimDir, /\.beadboard\/bin$/);
});
Step 2: Run test to verify it fails
Run:
node --import tsx --test tests/lib/runtime-manager.test.ts
Expected: FAIL (Cannot find module '../../src/lib/runtime-manager').
Step 3: Write minimal implementation
Implement exports:
normalizeVersion(version: string): stringgetRuntimePaths(home: string, version: string)resolveInstallHome(env)
Keep pure and side-effect free.
Step 4: Run test to verify it passes
Run:
node --import tsx --test tests/lib/runtime-manager.test.ts
Expected: PASS.
Step 5: Commit
git add src/lib/runtime-manager.ts tests/lib/runtime-manager.test.ts
git commit -m "feat(installer): add runtime manager core library"
Phase 3: Move Launcher to Runtime-Aware Execution
Task 3: Update launcher to run from managed runtime root
Files:
- Modify:
install/beadboard.mjs - Modify:
tests/scripts/beadboard-launcher.test.ts - Create:
tests/scripts/beadboard-launcher-runtime.test.ts
Step 1: Write failing test
import test from 'node:test';
import assert from 'node:assert/strict';
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
import path from 'node:path';
const execFileAsync = promisify(execFile);
const launcherPath = path.resolve('install/beadboard.mjs');
test('status --json reports runtime root and install mode', async () => {
const { stdout } = await execFileAsync(process.execPath, [launcherPath, 'status', '--json']);
const payload = JSON.parse(stdout);
assert.ok(payload.runtimeRoot);
assert.ok(payload.installMode);
});
Step 2: Run test to verify it fails
Run:
node --import tsx --test tests/scripts/beadboard-launcher-runtime.test.ts
Expected: FAIL (missing fields).
Step 3: Write minimal implementation
In launcher:
- derive runtime home/version
- include
runtimeRoot,installMode,shimTargetin JSON status - preserve existing
start/open/statusbehavior
Step 4: Run tests to verify pass
Run:
node --import tsx --test tests/scripts/beadboard-launcher.test.ts
node --import tsx --test tests/scripts/beadboard-launcher-runtime.test.ts
Expected: PASS.
Step 5: Commit
git add install/beadboard.mjs tests/scripts/beadboard-launcher.test.ts tests/scripts/beadboard-launcher-runtime.test.ts
git commit -m "feat(launcher): add runtime-aware status metadata"
Phase 4: Replace Repo-Bound Shim Targets
Task 4: Make install wrappers point at runtime-managed target
Files:
- Modify:
install/install.sh - Modify:
install/install.ps1 - Modify:
tests/scripts/install-wrappers-contract.test.ts - Modify:
tests/scripts/install-sh-smoke.test.ts - Create:
tests/scripts/install-legacy-migration.test.ts
Step 1: Write failing migration test
import test from 'node:test';
import assert from 'node:assert/strict';
// simulate legacy shim text and verify installer rewrites to runtime target
test('installer migrates legacy repo-bound shim to runtime-managed shim', async () => {
assert.fail('implement');
});
Step 2: Run test to verify it fails
Run:
node --import tsx --test tests/scripts/install-legacy-migration.test.ts
Expected: FAIL.
Step 3: Write minimal implementation
In both wrappers:
- install runtime metadata file (
~/.beadboard/runtime/current.json) - rewrite
bb/beadboardshims to resolve runtime target first - detect old shim signatures and replace atomically
Step 4: Run wrapper tests
Run:
node --import tsx --test tests/scripts/install-wrappers-contract.test.ts
node --import tsx --test tests/scripts/install-sh-smoke.test.ts
node --import tsx --test tests/scripts/install-legacy-migration.test.ts
Expected: PASS.
Step 5: Commit
git add install/install.sh install/install.ps1 tests/scripts/install-wrappers-contract.test.ts tests/scripts/install-sh-smoke.test.ts tests/scripts/install-legacy-migration.test.ts
git commit -m "feat(installer): migrate shims to runtime-managed targets"
Phase 5: Add npm-Global Entry and Self-Management Commands
Task 5: Add CLI entrypoint commands (self-update, uninstall, doctor)
Files:
- Modify:
package.json - Create:
bin/beadboard.js - Create:
src/cli/beadboard-cli.ts - Create:
tests/cli/beadboard-cli.test.ts
Step 1: Write failing CLI tests
import test from 'node:test';
import assert from 'node:assert/strict';
import { runCli } from '../../src/cli/beadboard-cli';
test('doctor returns structured install diagnostics', async () => {
const out = await runCli(['doctor', '--json']);
assert.equal(out.ok, true);
assert.ok(out.installMode);
});
Step 2: Run test to verify it fails
Run:
node --import tsx --test tests/cli/beadboard-cli.test.ts
Expected: FAIL (missing module/command).
Step 3: Write minimal implementation
Add commands:
beadboard doctor --jsonbeadboard self-update(placeholder behavior with explicit output if publish not configured)beadboard uninstall(remove shims/runtime with--yesguard)
Add bin mapping in package.json.
Step 4: Run test to verify pass
Run:
node --import tsx --test tests/cli/beadboard-cli.test.ts
Expected: PASS.
Step 5: Commit
git add package.json bin/beadboard.js src/cli/beadboard-cli.ts tests/cli/beadboard-cli.test.ts
git commit -m "feat(cli): add global entrypoint with doctor/update/uninstall commands"
Phase 6: Driver Alignment + Remediation UX Finalization
Task 6: Update driver preflight/remediation copy for npm-global-first flow
Files:
- Modify:
skills/beadboard-driver/scripts/lib/driver-lib.mjs - Modify:
skills/beadboard-driver/scripts/session-preflight.mjs - Modify:
tests/skills/beadboard-driver/resolve-bb.test.ts - Modify:
tests/skills/beadboard-driver/session-preflight.test.ts
Step 1: Write failing test assertion
Add expectation:
- remediation mentions
npm i -g beadboardas primary - install script remains fallback
Step 2: Run test to verify it fails
Run:
node --import tsx --test tests/skills/beadboard-driver/resolve-bb.test.ts
node --import tsx --test tests/skills/beadboard-driver/session-preflight.test.ts
Expected: FAIL (copy mismatch).
Step 3: Write minimal implementation
Update remediation strings to:
- npm-global install
- fallback installer wrapper
- BB_REPO override guidance
Step 4: Re-run tests
Run:
node --import tsx --test tests/skills/beadboard-driver/resolve-bb.test.ts
node --import tsx --test tests/skills/beadboard-driver/session-preflight.test.ts
Expected: PASS.
Step 5: Commit
git add skills/beadboard-driver/scripts/lib/driver-lib.mjs skills/beadboard-driver/scripts/session-preflight.mjs tests/skills/beadboard-driver/resolve-bb.test.ts tests/skills/beadboard-driver/session-preflight.test.ts
git commit -m "feat(driver): prefer npm-global remediation with installer fallback"
Phase 7: CI, Docs, and Release Readiness
Task 7: Expand CI smoke and operator docs for global model
Files:
- Modify:
.github/workflows/installer-smoke.yml - Modify:
README.md - Modify:
docs/adr/2026-03-03-runtime-manager-global-install.md - Create:
docs/ops/global-install-rollout.md - Modify:
tests/scripts/installer-ci-contract.test.ts - Modify:
tests/docs/installer-quickstart-contract.test.ts
Step 1: Write failing test updates
Add assertions for:
- npm-global command in docs
- runtime home path mentions
- CI step validating
beadboard doctor --json
Step 2: Run tests to verify fail
Run:
node --import tsx --test tests/scripts/installer-ci-contract.test.ts
node --import tsx --test tests/docs/installer-quickstart-contract.test.ts
Expected: FAIL.
Step 3: Write minimal implementation
Update docs and workflow:
- install paths
- migration notes
- recovery playbook
- supported platforms matrix
Step 4: Re-run tests
Run:
node --import tsx --test tests/scripts/installer-ci-contract.test.ts
node --import tsx --test tests/docs/installer-quickstart-contract.test.ts
Expected: PASS.
Step 5: Commit
git add .github/workflows/installer-smoke.yml README.md docs/adr/2026-03-03-runtime-manager-global-install.md docs/ops/global-install-rollout.md tests/scripts/installer-ci-contract.test.ts tests/docs/installer-quickstart-contract.test.ts
git commit -m "docs(ci): finalize global install runtime docs and smoke coverage"
Phase 8: Final Verification + Bead Closeout
Task 8: Full-gate verification and close
Files:
- Modify:
beadboardissue notes viabd update - Modify:
NEXT_SESSION_PROMPT.md
Step 1: Run full gates
Run:
npm run typecheck
npm run lint
npm run test
Expected: PASS; if unrelated failures exist, capture exact files/tests.
Step 2: Run targeted installer acceptance checks
Run:
node --import tsx --test tests/lib/runtime-manager.test.ts
node --import tsx --test tests/scripts/beadboard-launcher-runtime.test.ts
node --import tsx --test tests/scripts/install-legacy-migration.test.ts
node --import tsx --test tests/skills/beadboard-driver/resolve-bb.test.ts
Expected: PASS.
Step 3: Update beads with evidence
Run:
bd update <bead-id> --notes "<commands run + pass/fail details>"
bd close <bead-id> --reason "<completed outcome>"
Step 4: Update handoff
Modify:
NEXT_SESSION_PROMPT.mdwith shipped state + residual risks + next bead.
Step 5: Commit
git add NEXT_SESSION_PROMPT.md
git commit -m "chore: close runtime-manager rollout with verification evidence"
References and Required Skills During Execution
@test-driven-development@verification-before-completion@linus-beads-discipline@beadboard-driver@executing-plans(required for implementation phase)
Plan complete and saved to docs/plans/2026-03-03-global-install-runtime-manager.md. Two execution options:
1. Subagent-Driven (this session) - I dispatch fresh subagent per task, review between tasks, fast iteration
2. Parallel Session (separate) - Open new session with executing-plans, batch execution with checkpoints
Which approach?