feat(boatstack): managed workspace lifecycle (fresh cut + auto cleanup) - #68
Merged
Conversation
Add a workspace policy config block (enabled/mode/cleanup/cleanup_after) and the deterministic worktree/branch lifecycle it governs: fresh cut from the up-to-date default branch at feature start, and merge-gated, confirm-gated, safety-gated cleanup after ship. Managed unit is a git worktree or an in-place branch; the disabled zero value preserves prior hands-off behavior. - runtime.go: Workspace struct + ProjectConfig field - init.go: defaults for new installs (worktree/confirm/merge) - export.go: lenient enum validation (empty resolves to defaults) - workspace.go: CutFeatureWorkspace, CleanupFeatureWorkspace, FeatureWorkspaceStatus, gh->git merge-status fallback - cmd: internal workspace-cut/cleanup/status subcommands - workspace_test.go: 19 unit tests; full suite green
Surface workspace cleanup automatically instead of adding a command users must remember: boatstack-next routes a published feature to workspace-cleanup when management is on and its worktree still exists locally (local-only check; merge confirmation stays inside the operation). Add the internal workspace-cleanup operation prose and router entry (not a user-invocable skill), the c/k reply shortcuts and post-ship state contract in the canonical workflow, and a reader-facing release note. - next.go: FEATURE_COMPLETE -> workspace-cleanup routing, gated on workspace.enabled + a live worktree - workspace.go: workspaceEnabled helper - export.go: workspace-cleanup operation + adapter router vocabulary - references/workflow.md: state machine, reply shortcuts, state contract - workspace_test.go: routing tests (cleanup / none / disabled) - release note fragment
Route boatstack-next from an approved feature to workspace-cut before build when workspace.enabled and the working tree is still on the default branch, so work never starts on a stale base branch. A feature that already has its own branch or worktree is respected and goes straight to build. Local-only routing check; the cut itself fetches origin. - workspace.go: needsFreshCut helper - next.go: APPROVED -> workspace-cut routing (gated on enabled + on-base) - export.go: workspace-cut operation prose + router vocabulary - references/workflow.md: PLAN_APPROVED -> WORKSPACE_CUT contract + routing row - workspace_test.go: cut-routing tests (on-base / already-cut / disabled)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this change
Feedback from Boatstack usage: "Could Boatstack clean up worktrees when you're done? I never remember to, and it seems to slow down updates." Today Boatstack owns no worktree/branch lifecycle — it operates on whatever branch the human already made, so people forget to cut fresh and forget to clean up, and stale worktrees block
boatstack-update.This adds an opt-in managed workspace lifecycle woven into the flow the state machine already drives — not a command users must remember.
What changed
Config — new
workspaceblock (back-compat;enabled:false/ absent = today's exact hands-off behavior):enabled(master switch),mode(worktree|branch),cleanup(confirm|auto|off),cleanup_after(merge|ship). Validation is lenient — empty values resolve to defaults, so pre-existing configs stay valid.Fresh cut (feature start) —
boatstack-nextroutesAPPROVED → workspace-cutwhen management is on and you're still on the base branch, cutting a fresh branch/worktree from the freshly-fetched default branch. A workspace you cut yourself is respected and goes straight tobuild.Cleanup (after publish) —
boatstack-nextsurfacesworkspace-cleanuponce a feature is published and its worktree still exists locally. It checks merge status (gh→ local-ancestry fallback) and, in confirm mode, askscto clean /kto keep. It is merge-gated, confirm-gated, and safety-gated: never removes uncommitted/unmerged work without an explicit--force, never deletes remote branches, never merges.Both are internal operations, not user-invocable skills (deliberately excluded from
claudeVisibleSkills).ResolveNextstays GitHub-free — all routing checks are local-only.Review order
runtime.go/init.go/export.go— config schema, defaults, lenient validationworkspace.go— the lifecycle logic (cut, cleanup, status, gh→git merge fallback)cmd/boatstack-helper/main.go— internalworkspace-cut/workspace-cleanup/workspace-statusnext.go— routing (gated onworkspace.enabled+ local state)references/workflow.md— state machine,c/kreply shortcuts, contractsworkspace_test.go— 26 testsEvidence
go test ./... -count=1);gofmt+go vetcleancheck-policyPASSGaps and risks
cleanup_after: ship(clean before merge) is supported but niche; default ismerge.