Skip to content

Git-backed workspace storage — composes with #144 storage modes + #58 #147

@thomas-stegemann

Description

@thomas-stegemann

Why

#58 ("Git-native workspace") sits as a roadmap goal — a workspace's state (URLs, envs, collections, recordings, scripts, AI config overrides) should be checkable into a git repo so a team can git push / git pull their context.

After #116 (workspaces with per-user-folder scoping) + #144 (chunked recording storage with per-workspace roots) + #144 Phase 1.7 (per-workspace recording-storage mode), the architecture is almost there but on a different axis. We have:

A git-backed workspace adds a second axis: storage location. The two compose orthogonally.

Proposal — workspace.storageRoot

A workspace gains an optional storageRoot field:

{
  "id": "ws_payments",
  "name": "Payments — staging",
  "color": "#22c55e",
  "storageRoot": "/Users/me/work/payments/.bowire",  // ← NEW
  "recordingStorageMode": "both"
}

Resolution

  • When storageRoot is unset (today's default): recordings live at ~/.bowire/workspaces/<wsId>/recordings/. No change.
  • When storageRoot is set: recordings live at <storageRoot>/recordings/. Everything else (envs, collections, scripts) routes the same way.
  • Frontend sends storageRoot=... as a query param on every workspace-scoped API call (next to the existing workspaceId=...).
  • Backend's BowireUserContext.GetUserPath() gets an overload that accepts an explicit root; the resolution chain is storageRoot → multi-tenant per-identity → single-user default.

Operator surface

In the Workspaces rail-mode detail pane, add a Storage location section under the existing Recording storage section:

Field Behaviour
[unset] Default — user folder
<path> Custom — workspace state lives there
[+ Init git workspace…] Opens a dialog: pick a directory, run git init, set storageRoot to that path, drop a .gitignore excluding recordings/bodies/ (content-addressed blobs are large; let teams choose)

A "Sync to git" action (manual commit + push) can land later; for v1 the operator runs git commands themselves.

Composes with

Acceptance

  • workspace.storageRoot field persisted with the workspace.
  • Frontend sends storageRoot=... on every recording / env / collection API call when set.
  • Backend resolves to the configured root before falling back to the user folder.
  • Path sanitisation: reject paths that contain .. traversal or absolute paths outside the OS allow-list (configurable per host).
  • Workspaces rail-mode detail pane shows the current storage root + a "Browse…" button to change it.
  • [+ Init git workspace…] runs git init, drops a default .gitignore, sets storageRoot.
  • Save-pill carries the location label.
  • Migration is on-demand: switching from default → git-backed offers to copy the existing recordings + envs to the new root.

Out of scope

  • Auto-commit / auto-push on every change. Too noisy; the operator owns git operations.
  • Conflict resolution UI for git pull showing merge conflicts in the workbench. Operator handles in their git tooling.
  • Multi-root workspaces (one workspace pulling state from multiple git repos). Niche; defer until a real ask.
  • Cloud-hosted shared workspaces (S3, blob). Different storage class entirely; separate issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:workbenchUI / workbench surfaceroadmapTracked on the public Project board

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions