WSM Architecture Overview

High-level architecture map for commands, workflows, services, and JS integration.

Sections

Terminology & Glossary
📖 Documentation
Navigation
6 sectionsv0.1
📄 WSM Architecture Overview — glaze help wsm-architecture-overview
wsm-architecture-overview

WSM Architecture Overview

High-level architecture map for commands, workflows, services, and JS integration.

Topicworkspace-managerarchitecturerefactorall--output-mode

This page describes how the WSM codebase is organized. It is aimed at contributors who want to understand where behavior lives, how layers connect, and where to add new functionality.

Layering model

WSM follows a strict four-layer architecture. Each layer has a clear responsibility, and dependencies flow downward:

┌──────────────────────────────────────────────────┐
│  cmd/wsm/cmds/          CLI adapters             │
│    registry/   workspace/   git/   js/           │
├──────────────────────────────────────────────────┤
│  pkg/wsm/workflows/     Orchestration layer      │
│    create, status, commit, rebase, fork, ...     │
├──────────────────────────────────────────────────┤
│  pkg/wsm/               Core domain services     │
│    workspace, discovery, git_operations, branch/ │
├──────────────────────────────────────────────────┤
│  pkg/wsm/gitclient/     Git abstraction          │
│    cli backend (system git)                      │
└──────────────────────────────────────────────────┘

Layer 1: CLI adapters (cmd/wsm/cmds/)

Each Cobra command lives in a subpackage. Command files are thin: they decode flags into a settings struct, call a workflow, and format output. Business logic does not belong here.

Subpackages:

  • registry/ -- discover, list repos, list workspaces
  • workspace/ -- create, info, status, add, remove, fork, merge, delete
  • git/ -- commit, diff, log, branch (create/switch/list), rebase (start/status/continue/abort)
  • js/ -- runner

Shared infrastructure lives in cmd/wsm/cmds/common/:

  • build.go -- Glazed command description builder with standard sections
  • runtime.go -- --output-mode resolution and structured row emission

Layer 2: Workflows (pkg/wsm/workflows/)

Workflows are the orchestration layer. Each workflow encapsulates a complete user-facing operation and defines its own request/result types:

WorkflowPurpose
DiscoverWorkflowScan directories, update registry
CreateWorkflowResolve branches, create worktrees, write workspace config
StatusWorkflowGather git status across repos (parallelized with --jobs)
CommitWorkflowTwo-phase: Prepare() then Execute() for multi-repo commits
RebaseWorkflowRebase/status/continue/abort with conflict detection
ListWorkflowList repositories and workspaces
InfoWorkflowResolve workspace, extract field values
ForkWorkflowTwo-phase: Plan() then Fork()
DeleteWorkflowPreview then delete with worktree cleanup
MergeWorkflowMerge branches back and optionally clean up

Workflows own the sequencing of operations. They call into core domain services but never call CLI commands.

Layer 3: Core domain (pkg/wsm/)

The domain layer contains the foundational types and services:

  • types.go -- Repository, Workspace, RepositoryStatus, WorkspaceStatus, WorkspaceConfig
  • workspace.go -- WorkspaceManager with create, load, delete, detect operations
  • workspace_context.go -- Workspace detection from working directory
  • discovery.go -- Repository scanning logic
  • status.go -- StatusChecker for per-repo git status
  • git_operations.go -- Diff and other git operations
  • history_operations.go -- Log and commit history queries
  • branch_operations.go -- Create, switch, list branches across repos
  • rebase_operations.go -- Low-level rebase: start, continue, abort, detect state, list conflicts

Layer 4: Git client (pkg/wsm/gitclient/)

The git client provides an abstraction over git operations. WSM uses the system git CLI backend:

  • client.go -- Interface definition
  • cli_client.go -- Git operations via git CLI
  • worktree_cli.go -- Worktree operations via git worktree

Branch resolution system

Branch policy is centralized in pkg/wsm/branch/ to avoid duplicating branch decisions across commands. The system uses typed enums:

ResolutionMode -- what operation triggered the branch decision:

  • CreateWorktree -- creating a new workspace worktree
  • AddRepository -- adding a repo to an existing workspace
  • Sync -- syncing branches across a workspace

ResolutionStrategy -- how to obtain the target branch:

  • UseLocal -- use the existing local branch as-is
  • TrackRemote -- create a local tracking branch from remote
  • CreateFromBase -- create a new branch from the specified base
  • CreateFromHead -- create a new branch from HEAD

RemoteRefKind -- how to interpret remote references:

  • None -- no remote reference
  • RemoteTrackingBranch -- reference is remote/branch format

A BranchResolutionRequest goes in, a BranchResolutionPlan comes out. The plan is deterministic: same inputs always produce the same strategy. Commands and workflows use the branch service rather than implementing their own logic.

JS integration

The JavaScript layer lives in pkg/wsmjs/ and mirrors the CLI/workflow architecture:

pkg/wsmjs/
├── service/    Manager facade wrapping workflows
├── module/     goja native module (require("wsm"))
└── runner/     Script file loader and executor
  • service/manager.go -- The Manager struct wraps workflow instances and provides a flat Go API: Discover, CreateWorkspace, Status, ListWorkspaces, ListRepositories.
  • module/module.go -- Registers a goja native module that maps JS calls to service methods. Handles type conversion between Go and JS via JSON round-trip.
  • runner/runner.go -- RunFile() bootstraps a goja runtime, registers the wsm module, loads and executes a script file, and returns its result.

The key design decision is that the JS API calls the same workflow layer as the CLI. There are no separate implementations -- require("wsm").createWorkspace() and wsm create both go through CreateWorkflow.

Output model

All commands use the shared output mode system defined in cmd/wsm/cmds/common/runtime.go:

  • ShouldOutputHuman(mode) -- true for human and both modes
  • ShouldOutputData(mode) -- true for data and both modes
  • EmitRows(ctx, vals, rows) -- emits structured data through Glazed

Commands typically have two output blocks: one for human-readable text (headers, tables, status messages) and one for structured rows. The both mode runs them sequentially.

Adding a new command

  1. Create the settings struct and command in the appropriate cmd/wsm/cmds/ subpackage.
  2. Create a workflow in pkg/wsm/workflows/ with request/result types.
  3. The workflow should call core services from pkg/wsm/, not implement git logic directly.
  4. Wire the command into cmd/wsm/root.go.
  5. If the operation should be available from JS, add a method to pkg/wsmjs/service/manager.go and expose it in pkg/wsmjs/module/module.go.

Troubleshooting

ProblemCauseSolution
New command has lots of business logicLogic added in cmd/ instead of workflowMove orchestration into pkg/wsm/workflows/
Duplicate branch decisionsBranch policy bypassedRoute through pkg/wsm/branch/ service
JS API diverges from CLI behaviorSeparate code pathsBoth must call the same workflow
Rebase state detection failsMissing .git/rebase-merge checkSee rebase_operations.go for state detection logic

See Also

  • wsm help wsm-command-reference
  • wsm help wsm-persistence-and-state
  • wsm help wsm-js-api-and-runner