Skip to content

Add repository-based thread organization#1318

Open
ebg1223 wants to merge 5 commits into
getpaseo:mainfrom
ebg1223:codex/sidebar-agent-rows-option-2
Open

Add repository-based thread organization#1318
ebg1223 wants to merge 5 commits into
getpaseo:mainfrom
ebg1223:codex/sidebar-agent-rows-option-2

Conversation

@ebg1223
Copy link
Copy Markdown
Contributor

@ebg1223 ebg1223 commented Jun 3, 2026

What changes

This adds a workspace organization preference for how the app presents active work.

The existing Workspaces organization remains the default. It keeps the current sidebar behavior: projects expand into workspaces/branches, and workspace tabs continue to represent the active work for that workspace.

The new Threads organization gives users a repo-centered way to work when several unrelated agent tasks are happening in the same checkout. In this mode:

  • The sidebar shows repositories/projects with active threads underneath.
  • Thread rows show their branch/workspace context and status.
  • Opening a thread creates or focuses a view tab for that thread.
  • Closing a tab only hides that view; it does not archive the thread.
  • Closing a thread from the sidebar archives it and removes it from active lists.
  • Repository rows can start a new thread in an existing workspace/branch, including when that branch does not currently have any active thread.

Workspace-specific organization still exists where it is useful. Status grouping and numbered workspace shortcuts remain tied to the default Workspaces organization, where those controls still map directly to visible workspace rows.

Why

Worktrees are not always the right organizing boundary. Users may run multiple unrelated tasks from the same checkout and resolve conflicts later, which makes branch/workspace tabs a weak proxy for the work they are actually switching between.

This keeps the current workflow intact while adding an alternate organization that treats threads as the primary units of work.

ebg1223 added 2 commits June 3, 2026 00:53
…-rows-option-2

# Conflicts:
#	packages/app/src/components/left-sidebar.tsx
#	packages/app/src/components/sidebar-workspace-list.tsx
#	packages/app/src/components/workspace-shortcut-targets-subscriber.tsx
#	packages/app/src/screens/workspace/workspace-screen.tsx
#	packages/app/src/utils/sidebar-shortcuts.test.ts
#	packages/app/src/utils/sidebar-shortcuts.ts
@ebg1223 ebg1223 changed the title [codex] Make thread-first sidebar optional Add repository-based thread organization Jun 3, 2026
@ebg1223 ebg1223 marked this pull request as ready for review June 4, 2026 06:26
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Jun 4, 2026

Greptile Summary

This PR adds a thread-first workspace organization mode alongside the existing workspace-first default. The feature is controlled by a new WorkspaceOrganizationPolicy that drives sidebar presentation, tab scoping, agent auto-open behavior, and close semantics throughout the app.

  • A new workspace-organization-store.ts owns the mode preference (persisted via AsyncStorage) and exposes a getWorkspaceOrganizationPolicy function that maps the two modes to a concrete policy object; all downstream code reads from that object rather than branching on the mode string directly.
  • Tab targets now carry an optional workspaceId context field, enabling project-scoped persistence keys in thread-first mode; the allowArchived flag on agent tabs replaces pinning as the mechanism for keeping archived agent views alive through reconciliation.
  • autoOpenAgentIds is extracted out of deriveWorkspaceAgentVisibility and computed externally in WorkspaceScreenContent, making the visibility derivation mode-agnostic and giving each mode explicit control over which agents receive automatic tabs.

Confidence Score: 5/5

The new mode is fully opt-in and the default workspace-first path is unchanged, making this safe to merge.

All behavioral changes are gated by the organization policy. The workspace-first path is extensively tested and the new thread-first path has targeted new tests covering allowArchived tab persistence, project-scoped visibility, and bulk-close copy differences.

packages/app/src/workspace-tabs/identity.ts — the file-tab equality change has an asymmetry with the deterministic tab ID that could produce silent retargeting in project-scoped mode.

Important Files Changed

Filename Overview
packages/app/src/stores/workspace-organization-store.ts New store: persists mode preference, exports policy factory. Clean design – two concrete policy constants, a normalizer for safe deserialization, and a custom merge for Zustand persist.
packages/app/src/workspace-tabs/agent-visibility.ts Removes autoOpenAgentIds from WorkspaceAgentVisibility; adds deriveProjectAgentVisibility for project-scoped agent inclusion. The fallback-only-when-no-workspaces guard keeps the function safe during initial load.
packages/app/src/stores/workspace-layout-actions.ts autoOpenAgentIds made optional (defaults to []); workspaceId added to snapshots; terminal tab collapse guarded by workspaceId match; allowArchived exemption in collapseStaleEntityTabs; applyPinnedAndHidden guard changed from knownAgentIds to baseAgentIds.
packages/app/src/workspace-tabs/identity.ts workspaceTabTargetsEqual now includes workspaceId for file tabs and allowArchived for agent tabs; buildDeterministicWorkspaceTabId still uses path only for file tabs, creating an asymmetry with the new equality check.
packages/app/src/screens/workspace/workspace-screen.tsx Switches between workspace-scoped and project-scoped persistence keys; computes autoOpenAgentIds externally via useMemo; threads workspaceId context into all tab opens.
packages/app/src/stores/workspace-tabs-store/state.ts Adds workspaceId? to all tab target kinds; new buildWorkspaceProjectTabScopeKey for project-scoped keys; coerce helpers refactored from if-chain to switch.
packages/app/src/hooks/sidebar-workspaces-view-model.ts Adds SidebarAgentEntry, buildSidebarProjectsWithAgents, and normalizeSidebarBranchName. Agent projection and sorting logic is well-isolated.
packages/app/src/utils/workspace-navigation.ts resolvePreparedTabScopeKey reads the organization policy at call time and builds the correct persistence key.
packages/app/src/screens/workspace/workspace-bulk-close.ts archiveAgentTabs flag added; UI copy now differs by mode; correctly skips agent closeItems RPC when not archiving.
packages/app/src/utils/sidebar-project-row-model.ts isSidebarProjectFlattened and buildSidebarProjectRowModel accept organizationMode; collapsibility logic branches correctly between modes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Store["useWorkspaceOrganizationStore\n(persisted mode: workspace-first | thread-first)"]
    Policy["getWorkspaceOrganizationPolicy(mode)\n→ WorkspaceOrganizationPolicy"]
    Store --> Policy

    Policy -->|tabScope: workspace| WPK["workspacePersistenceKey\n(serverId:workspaceId)"]
    Policy -->|tabScope: project| PPK["projectTabScopeKey\n(serverId:project:projectKey)"]

    WPK -->|workspace-first| Reconcile
    PPK -->|thread-first| Reconcile

    Policy -->|agentVisibilityScope: workspace| WAV["deriveWorkspaceAgentVisibility"]
    Policy -->|agentVisibilityScope: project| PAV["deriveProjectAgentVisibility"]

    WAV --> AutoOpen
    PAV --> AutoOpen

    Policy -->|agentTabPopulation: auto-active| AutoOpen["autoOpenAgentIds\n(shouldAutoOpenAgentTab filter)"]
    Policy -->|agentTabPopulation: manual-open| EmptySet["EMPTY_SET"]

    AutoOpen --> Reconcile["reconcileWorkspaceTabs\n(WorkspaceTabSnapshot)"]
    EmptySet --> Reconcile

    Reconcile --> CollapseStale["collapseStaleEntityTabs\n(allowArchived exemption)"]
    Reconcile --> AddMissing["addMissingEntityTabs\n(workspaceId context on tabs)"]

    Policy -->|agentTabClose: archive-root| CloseArchive["resolveCloseAgentTabPolicy\n(archive root, layout-only sub)"]
    Policy -->|agentTabClose: layout-only| CloseLayout["layout-only for all tabs"]
Loading

Reviews (3): Last reviewed commit: "Merge remote-tracking branch 'upstream/m..." | Re-trigger Greptile

Comment on lines +26 to +36
export interface SidebarAgentWorkspaceSource {
id: string;
projectId: string;
projectRootPath: string;
workspaceDirectory: string;
projectKind: WorkspaceDescriptor["projectKind"];
workspaceKind: WorkspaceDescriptor["workspaceKind"];
name: string;
gitRuntime?: { currentBranch?: string | null } | null;
project?: ProjectPlacementPayload;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Duplicate SidebarAgentWorkspaceSource interface

The same interface name is defined independently here (with project?: ProjectPlacementPayload) and in session-store-hooks/selectors.ts (with project?: WorkspaceDescriptor["project"]). Because TypeScript uses structural typing, they compile together today, but the project field types can diverge silently. use-sidebar-workspaces-list.ts re-exports the model version while useSidebarAgentWorkspaces returns the selectors version — callers that care about project already see two different shapes. One canonical definition should own the type; the other should import and re-export it.

Rule Used: # Code Review Pattern Reference: Slop, Tests, Feat... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread packages/app/src/screens/settings-screen.tsx Outdated
ebg1223 added 2 commits June 4, 2026 00:16
…-rows-option-2

# Conflicts:
#	packages/app/src/components/left-sidebar.tsx
#	packages/app/src/components/sidebar-workspace-list.tsx
#	packages/app/src/hooks/sidebar-workspaces-view-model.test.ts
#	packages/app/src/hooks/sidebar-workspaces-view-model.ts
#	packages/app/src/hooks/use-sidebar-workspaces-list.ts
#	packages/app/src/stores/session-store-hooks/selectors.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant