-
Notifications
You must be signed in to change notification settings - Fork 4
Refactor session/orchestrator management and simplify zellij package #261
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
newhook
merged 19 commits into
main
from
feat/refactor-session-and-orchestrator-management-for-c
Feb 1, 2026
Merged
Refactor session/orchestrator management and simplify zellij package #261
newhook
merged 19 commits into
main
from
feat/refactor-session-and-orchestrator-management-for-c
Feb 1, 2026
Conversation
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
- Add SessionNameForProject and FormatTabName to internal/project - Update claude package to delegate to project (maintains backward compat) - Update control/spawn.go to use project package directly - This breaks the import cycle between claude and control packages Closes: ac-7xrb.1 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create internal/work/orchestrator.go with OrchestratorManager interface, DefaultOrchestratorManager, and orchestrator functions (SpawnWorkOrchestrator, EnsureWorkOrchestrator, TerminateWorkTabs) - Remove duplicate functions from claude/runner.go - Delete obsolete claude/orchestrator.go and claude/orchestrator_mock.go - Update work/service.go to use local OrchestratorManager - Update work/work.go to use local TerminateWorkTabs - Update control/plane.go to use work.SpawnWorkOrchestrator - Update testutil/harness.go to use work.OrchestratorManagerMock - Update tui/tui_plan_work.go to use work.EnsureWorkOrchestrator - Regenerate mocks Closes: ac-7xrb.2 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updated SpawnWorkOrchestrator, OpenConsole, OpenClaudeSession, and SpawnPlanSession to require that the zellij session already exists: - Replace zc.EnsureSession() calls with zc.SessionExists() checks - Return error if session doesn't exist, guiding caller to use control.InitializeSession or control.EnsureControlPlane - Add documentation noting that callers must initialize the session This ensures sessions are never created without control planes, which was the issue when EnsureSession created bare sessions. Closes: ac-7xrb.4 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove EnsureSession and CreateSession from SessionManager interface - Update SpawnControlPlane to assume session already exists - All session creation now goes through EnsureSessionWithLayout - Regenerate zellij mock Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move OpenConsole, OpenClaudeSession, SpawnPlanSession, PlanTabName to work/tabs.go - Remove deprecated SessionNameForProject and FormatTabName wrappers - Update cmd/work.go and internal/tui/tui_plan_work.go to use work package - Claude package now only contains prompt building and Claude runner code Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move EnsureControlPlane() before OpenConsole() in tui_plan_work.go to ensure the zellij session exists before attempting to open a console pane. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Eliminates package-level functions that encouraged bypassing the OrchestratorManager interface. All tab operations now go through the interface for proper dependency injection and testability. Changes: - Convert TerminateWorkTabs, SpawnWorkOrchestrator, EnsureWorkOrchestrator to DefaultOrchestratorManager methods in orchestrator.go - Convert OpenConsole, OpenClaudeSession, SpawnPlanSession to DefaultOrchestratorManager methods in tabs.go - Update TUI to use workService.OrchestratorManager for all tab ops - Update control plane to pass DB to NewControlPlane for spawner - Update CLI commands to create OrchestratorManager locally Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create internal/session package with Initialize, EnsureControlPlane, SpawnControlPlane (extracted from control/spawn.go) - Add CreateWorkFromBead to WorkService encapsulating common work creation logic (expand beads, create work, init session, ensure CP) - Update CollectIssueIDsForAutomatedWorkflow to accept beads.Reader interface instead of *beads.Client - Simplify TUI executeCreateWork to use CreateWorkFromBead - Update CLI commands (work.go, run.go, work_import_pr.go) to use session package directly - control/spawn.go now delegates to session package (backward compat) This breaks the import cycle: work -> session, control -> work (no cycle) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move ImportPRAsync from standalone function to WorkService method - Move DestroyWork from standalone function to WorkService method - Remove duplicate CreateWorkAsync, keep only CreateWorkAsyncWithOptions - Update WorkDestroyer interface to not require project parameter - Change NewControlPlane to take *project.Project instead of *db.DB This eliminates code duplication and makes the WorkService API consistent. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Session interface had methods that were only used internally by the Client struct but never called from outside the zellij package: - WriteASCII, WriteChars, SendEnter, ExecuteCommand (low-level input) - SendCtrlC (replaced session.go usage with TerminateAndCloseTab) - RunFloating, ToggleFloatingPanes, Run (floating pane operations) This reduces the interface surface area and mock complexity (~430 lines removed from zellij_mock.go). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
External callers should use the SessionManager interface, not the concrete Client type. This enforces proper abstraction and makes mocking easier. - Renamed Client to client (private) - New() now returns SessionManager instead of *Client - Updated tests to use type assertion for internal field access Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of session delegating to client methods, session now contains the actual implementation directly. This eliminates the unnecessary indirection where every session method just called the corresponding client method with the session name. - session struct now holds config values (copied from client on creation) - All tab/pane operations implemented directly on session - client only handles session-level operations (list, exists, create) - Helper methods (writeASCII, sendCtrlC, etc.) are now private on session - Added test to verify session inherits config from client Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The struct implementing SessionManager interface should be named sessionManager, not client. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removed methods that were never called externally: - CreateTab (only CreateTabWithCommand is used) - CloseTab (only used internally by TerminateAndCloseTab) - TerminateProcess (only used internally by TerminateAndCloseTab) - ClearAndExecute (never used) Also removed: - ASCIIEnter constant (was only used by removed methods) - writeChars, sendEnter, executeCommand helpers (only used by ClearAndExecute) - CommandDelay and SessionStartWait fields from session struct (not used) The Session interface is now minimal: CreateTabWithCommand, SwitchToTab, QueryTabNames, TabExists, and TerminateAndCloseTab. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Delete control/spawn.go and update all callers to use session package directly. This eliminates the unnecessary indirection layer. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
EnsureControlPlane now returns (*InitResult, error) instead of just error, eliminating the need for callers to call both functions. Also made spawnControlPlane private since it's only used internally. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove the session package entirely by moving EnsureControlPlane into control. The work package no longer calls EnsureControlPlane - callers are now responsible for ensuring the control plane is running. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove prImporter struct, move methods directly to WorkService - Remove FetchPRMetadata passthrough, callers use GitHubClient directly - Fix CreateBeadFromPR to use BeadsReader instead of shelling out to bd CLI - Rename AddBeadsInternal to addBeadsInternal (unexported) - Add GitHubClient and BeadsDir fields to WorkService - Update handler_import_pr to use WorkService instead of creating separate instances Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ommands Fix bugs where OpenClaudeSession and OpenConsole were called without prior session initialization. With the new session existence checks, these would fail if the zellij session doesn't exist. - internal/tui/tui_plan_work.go: Add EnsureControlPlane() to openClaude() - cmd/work.go: Add EnsureControlPlane() to runWorkConsole() and runWorkClaude() Closes: ac-7xrb.8, ac-7xrb.9 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.
Summary
This PR refactors the codebase to establish cleaner package boundaries, consistent session management, and proper dependency injection:
controlpackage -EnsureControlPlanelives in control/spawn.go, no separate session package neededCreateWorkFromBeadshared method to WorkService encapsulating common steps: expand beads and create work asyncSessionNameForProject,FormatTabName) frominternal/claude/runner.gotointernal/project/to break import cyclesinternal/claude/tointernal/work/- orchestration naturally belongs with work lifecycle managementEnsureSessionfrom zellij public API - all session creation now goes throughEnsureSessionWithLayoutto ensure every session has a control plane tabOpenConsole,OpenClaudeSession, andSpawnPlanSessionto work packageEnsureControlPlanecalls before session-dependent operationsImportPRAsyncandDestroyWorkfrom standalone functions to WorkService methodsChanges
Package Restructuring
claude/runner.goproject/project.goSessionNameForProject(),FormatTabName()claude/orchestrator.gowork/orchestrator.goOrchestratorManagerinterface and implementationclaude/runner.gowork/tabs.goOpenConsole(),OpenClaudeSession(),SpawnPlanSession(),TerminateWorkTabs()Session Management
EnsureControlPlaneincontrol/spawn.gohandles all session/control plane lifecycle*InitResultwithSessionCreatedandSessionNamefor callers that need session infocontrol.EnsureControlPlaneworkpackage no longer manages sessions - it just creates work recordsWorkService Consolidation
CreateWorkFromBeadencapsulates bead expansion and async work creationEnsureControlPlaneseparately (cleaner separation of concerns)ImportPRAsyncandDestroyWorkmoved toWorkServicemethodsCreateWorkAsync- useCreateWorkAsyncWithOptionsinsteadZellij Package Simplification
Session interface reduced to 5 methods:
CreateTabWithCommand- create tab running a commandSwitchToTab- switch to named tabQueryTabNames- list all tabsTabExists- check if tab existsTerminateAndCloseTab- terminate process and close tabArchitecture changes:
ClienttosessionManager(private)New()returnsSessionManagerinterfaceBug Fixes
EnsureControlPlanenow called beforeOpenConsoleEnsureControlPlanecall beforeOpenClaudeSessionEnsureControlPlanecalls toco work consoleandco work claudecommandsAPI Changes
zellij.SessionManagerno longer exposesEnsureSession()orCreateSession()SpawnWorkOrchestrator,OpenConsolecheck that session exists and error if notOrchestratorManagerCollectIssueIDsForAutomatedWorkflowacceptsbeads.ReaderinterfaceIssues Resolved
Breaking Changes
zellij.SessionManager.EnsureSession()andCreateSession()are no longer availableclaude.OrchestratorManagermoved towork.OrchestratorManagerclaude.SessionNameForProject()andclaude.FormatTabName()moved toprojectpackageOpenConsole,OpenClaudeSession, etc.) moved fromclaudetoworkpackageTest Plan
go test ./...)co work consoleandco work claudecommands work with existing sessions🤖 Generated with Claude Code