Documentation
¶
Overview ¶
Package session manages Claude Code sessions and their git worktrees.
Overview ¶
Each session in Plural runs in its own git worktree, allowing multiple parallel Claude Code conversations to work on the same repository without conflicts. This package handles the creation and validation of these sessions.
Session Lifecycle ¶
1. Create: When a new session is created:
- A UUID is generated for the session ID
- A new git branch is created: plural-<UUID>
- A worktree is created under the centralized data directory (~/.plural/worktrees/<UUID> or XDG_DATA_HOME/plural/worktrees/<UUID>)
- The session is registered in the config
2. Resume: When resuming an existing session:
- The session's worktree path and branch are retrieved from config
- Claude CLI is started with --resume flag to continue the conversation
3. Delete: When a session is deleted:
- The session is removed from config
- Message history file is deleted
- The git worktree remains (allowing manual recovery if needed)
Worktree Structure ¶
Session worktrees are stored in a centralized location:
~/.plural/worktrees/<session-uuid>/
Or when using XDG Base Directory Specification:
$XDG_DATA_HOME/plural/worktrees/<session-uuid>/
This centralized location avoids scattering .plural-worktrees directories across the filesystem. Legacy worktrees from the old sibling-directory layout are automatically migrated on startup.
Git Operations ¶
The package uses git commands for:
- Creating worktrees: git worktree add -b <branch> <path>
- Validating repos: git rev-parse --git-dir
- Finding repo root: git rev-parse --show-toplevel
Functions ¶
Create: Creates a new session with a git worktree for the given repo path.
ValidateRepo: Checks if a path is a valid git repository.
GetGitRoot: Returns the git root directory for a path.
GetCurrentDirGitRoot: Returns the git root of the current working directory.
MigrateWorktrees: Migrates legacy worktrees to the centralized directory.
Index ¶
- Constants
- func ValidateBranchName(branch string) error
- type BasePoint
- type OrphanedWorktree
- type SessionService
- func (s *SessionService) BranchExists(ctx context.Context, repoPath, branch string) bool
- func (s *SessionService) Create(ctx context.Context, repoPath string, customBranch string, branchPrefix string, ...) (*config.Session, error)
- func (s *SessionService) CreateFromBranch(ctx context.Context, repoPath string, sourceBranch string, customBranch string, ...) (*config.Session, error)
- func (s *SessionService) Delete(ctx context.Context, sess *config.Session) error
- func (s *SessionService) FetchOrigin(ctx context.Context, repoPath string) error
- func (s *SessionService) GetCurrentDirGitRoot(ctx context.Context) string
- func (s *SessionService) GetDefaultBranch(ctx context.Context, repoPath string) string
- func (s *SessionService) GetGitRoot(ctx context.Context, path string) string
- func (s *SessionService) MigrateWorktrees(ctx context.Context, cfg *config.Config) error
- func (s *SessionService) PruneOrphanedWorktrees(ctx context.Context, cfg *config.Config) (int, error)
- func (s *SessionService) ValidateRepo(ctx context.Context, path string) error
Constants ¶
const MaxBranchNameValidation = 100
MaxBranchNameValidation is the maximum length for user-provided branch names. This is more permissive than git.MaxBranchNameLength which is for auto-generated names.
Variables ¶
This section is empty.
Functions ¶
func ValidateBranchName ¶
ValidateBranchName checks if a branch name is valid for git
Types ¶
type BasePoint ¶
type BasePoint string
BasePoint specifies where to branch from when creating a new session
const ( // BasePointOrigin branches from origin's default branch (after fetching) BasePointOrigin BasePoint = "origin" // BasePointHead branches from the current local HEAD BasePointHead BasePoint = "head" // BasePointLocalDefault branches from the local default branch (e.g., main) without fetching BasePointLocalDefault BasePoint = "local-default" )
type OrphanedWorktree ¶
type OrphanedWorktree struct {
Path string // Full path to the worktree
RepoPath string // Parent repo path (derived from .plural-worktrees location)
ID string // Session ID (directory name)
}
OrphanedWorktree represents a worktree that has no matching session
func FindOrphanedWorktrees ¶
func FindOrphanedWorktrees(cfg *config.Config) ([]OrphanedWorktree, error)
FindOrphanedWorktrees finds all worktrees in .plural-worktrees directories that don't have a matching session in config. Directory scans are parallelized for better performance with many repos.
type SessionService ¶
type SessionService struct {
// contains filtered or unexported fields
}
SessionService provides session operations with explicit dependency injection. Instead of using a package-level executor variable, each SessionService instance holds its own executor, enabling proper testing and avoiding global state.
func NewSessionService ¶
func NewSessionService() *SessionService
NewSessionService creates a new SessionService with the default real executor.
func NewSessionServiceWithExecutor ¶
func NewSessionServiceWithExecutor(exec pexec.CommandExecutor) *SessionService
NewSessionServiceWithExecutor creates a new SessionService with a custom executor. This is primarily used for testing where a mock executor is needed.
func (*SessionService) BranchExists ¶
func (s *SessionService) BranchExists(ctx context.Context, repoPath, branch string) bool
BranchExists checks if a branch already exists in the repo
func (*SessionService) Create ¶
func (s *SessionService) Create(ctx context.Context, repoPath string, customBranch string, branchPrefix string, basePoint BasePoint) (*config.Session, error)
Create creates a new session with a git worktree for the given repo path. If customBranch is provided, it will be used as the branch name; otherwise a branch named "plural-<UUID>" will be created. The branchPrefix is prepended to auto-generated branch names (e.g., "zhubert/"). The basePoint specifies where to branch from:
- BasePointOrigin: fetches from origin and branches from origin's default branch
- BasePointHead: branches from the current local HEAD
func (*SessionService) CreateFromBranch ¶
func (s *SessionService) CreateFromBranch(ctx context.Context, repoPath string, sourceBranch string, customBranch string, branchPrefix string) (*config.Session, error)
CreateFromBranch creates a new session forked from a specific branch. This is used when forking an existing session - the new worktree is created from the source branch's current state rather than from origin/main. If customBranch is provided, it will be used as the new branch name; otherwise a branch named "plural-<UUID>" will be created.
func (*SessionService) FetchOrigin ¶
func (s *SessionService) FetchOrigin(ctx context.Context, repoPath string) error
FetchOrigin fetches the latest changes from origin Returns nil if successful, or if there's no remote (local-only repo)
func (*SessionService) GetCurrentDirGitRoot ¶
func (s *SessionService) GetCurrentDirGitRoot(ctx context.Context) string
GetCurrentDirGitRoot returns the git root of the current working directory
func (*SessionService) GetDefaultBranch ¶
func (s *SessionService) GetDefaultBranch(ctx context.Context, repoPath string) string
GetDefaultBranch returns the default branch name for the remote (e.g., "main" or "master") Returns "main" as fallback if it cannot be determined
func (*SessionService) GetGitRoot ¶
func (s *SessionService) GetGitRoot(ctx context.Context, path string) string
GetGitRoot returns the git root directory for a path, or empty string if not a git repo
func (*SessionService) MigrateWorktrees ¶
MigrateWorktrees moves worktrees from old .plural-worktrees sibling directories to the centralized worktrees directory (~/.plural/worktrees/ or XDG equivalent). This is safe to call on every startup — it only acts when old-style worktrees exist.
func (*SessionService) PruneOrphanedWorktrees ¶
func (s *SessionService) PruneOrphanedWorktrees(ctx context.Context, cfg *config.Config) (int, error)
PruneOrphanedWorktrees removes all orphaned worktrees and their branches. Pruning operations are parallelized across repos, but serialized within each repo to avoid concurrent git operations on the same repository.
func (*SessionService) ValidateRepo ¶
func (s *SessionService) ValidateRepo(ctx context.Context, path string) error
ValidateRepo checks if a path is a valid git repository