Removing a workspace from Braid and destroying its files are two different decisions, but Studio only offers the second one. Someone who wants Braid to stop tracking a directory has to let Braid rm -rf it, or edit workspaces.json by hand.
What Exists Today
DELETE /workspaces/:workspaceId already models both outcomes.
const purge = context.req.query('purge') === 'true'
const workspace = await deps.workspaceService.findById(workspaceId)
await deps.workspaceService.remove(workspace.rootPath)
if (purge)
await rm(workspace.rootPath, { recursive: true, force: true })
Unregister is the base case. ?purge=true additionally destroys the folder.
Studio never calls the base case. api.deleteWorkspace hardcodes the flag, and the only caller is the delete action in WorkspaceDetailsSheet. So the unregister-only path has no way in.
Why A Button Is Not Enough
For a workspace living under <braidHome>/workspaces, unregistering without purging does not survive a restart. discoverCanonicalWorkspaces walks that directory on every boot and registers every subdirectory holding a PRODUCT.md, so the entry comes straight back.
That makes the two outcomes asymmetric in a way the API does not admit:
- A workspace registered from a path outside the canonical root stays unregistered.
- A workspace under the canonical root re-registers itself on the next boot, silently undoing what the user asked for.
Auto-discovery is the right default, it is what lets a CLI-created or hand-copied workspace show up without an explicit register step. The gap is that nothing records the user's intent to keep a directory out.
Open Decisions
- Where the intent lives. A marker file inside the workspace (
.braid-ignore), an ignore list in workspaces.json, or a discoverable: false field on the registry entry. A marker file travels with the directory when it is copied, a registry entry does not, and the two answer differently for someone who moves the folder between machines.
- Whether unregister is offered at all for a canonical-root workspace. Refusing it is honest, since the alternative is a control that does nothing after a restart. Offering it requires whichever mechanism the decision above picks.
- What the two actions are called. They need distinct names that state the consequence, since "Delete" alone cannot cover both. The transcript-level equivalent settled on a single
Delete that always destroys, with no flag, because its base case had no use. That reasoning does not carry here, both cases are wanted.
Acceptance
- A workspace can be removed from Braid with its directory left untouched, and it stays removed across a restart.
- Destroying the directory stays available and stays clearly distinct from removing the entry.
- A workspace registered from outside the canonical root behaves the same as one inside it.
- Auto-discovery still picks up a workspace nobody asked Braid to forget.
Removing a workspace from Braid and destroying its files are two different decisions, but Studio only offers the second one. Someone who wants Braid to stop tracking a directory has to let Braid
rm -rfit, or editworkspaces.jsonby hand.What Exists Today
DELETE /workspaces/:workspaceIdalready models both outcomes.Unregister is the base case.
?purge=trueadditionally destroys the folder.Studio never calls the base case.
api.deleteWorkspacehardcodes the flag, and the only caller is the delete action inWorkspaceDetailsSheet. So the unregister-only path has no way in.Why A Button Is Not Enough
For a workspace living under
<braidHome>/workspaces, unregistering without purging does not survive a restart.discoverCanonicalWorkspaceswalks that directory on every boot and registers every subdirectory holding aPRODUCT.md, so the entry comes straight back.That makes the two outcomes asymmetric in a way the API does not admit:
Auto-discovery is the right default, it is what lets a CLI-created or hand-copied workspace show up without an explicit register step. The gap is that nothing records the user's intent to keep a directory out.
Open Decisions
.braid-ignore), an ignore list inworkspaces.json, or adiscoverable: falsefield on the registry entry. A marker file travels with the directory when it is copied, a registry entry does not, and the two answer differently for someone who moves the folder between machines.Deletethat always destroys, with no flag, because its base case had no use. That reasoning does not carry here, both cases are wanted.Acceptance