diff --git a/apps/desktop/src/settings/DesktopClientSettings.test.ts b/apps/desktop/src/settings/DesktopClientSettings.test.ts
index 4867d8524093..611b4f795b3c 100644
--- a/apps/desktop/src/settings/DesktopClientSettings.test.ts
+++ b/apps/desktop/src/settings/DesktopClientSettings.test.ts
@@ -19,6 +19,7 @@ const clientSettings: ClientSettings = {
browserDefaultAppearance: "dark",
browserAutoShowFloatingPreview: false,
compactLegacySidebarStatuses: false,
+ showThreadWorktreeIndicators: true,
confirmQuit: true,
confirmThreadArchive: true,
confirmThreadDelete: false,
diff --git a/apps/desktop/src/settings/LastCodeSettingsImport.test.ts b/apps/desktop/src/settings/LastCodeSettingsImport.test.ts
index f2ff48a9ae4c..756323d221fa 100644
--- a/apps/desktop/src/settings/LastCodeSettingsImport.test.ts
+++ b/apps/desktop/src/settings/LastCodeSettingsImport.test.ts
@@ -92,6 +92,7 @@ describe("LastCodeSettingsImport", () => {
const lastCodeCustom = ProviderInstanceId.make("lastcode_custom");
const sourceClient = { ...DEFAULT_CLIENT_SETTINGS, fontSizeInterface: 17 };
Reflect.deleteProperty(sourceClient, "compactLegacySidebarStatuses");
+ Reflect.deleteProperty(sourceClient, "showThreadWorktreeIndicators");
Reflect.deleteProperty(sourceClient, "legacySidebarScale");
Reflect.deleteProperty(sourceClient, "roundedProjectIcons");
sourceClient.favorites = [
@@ -105,6 +106,7 @@ describe("LastCodeSettingsImport", () => {
const destinationClient = {
...DEFAULT_CLIENT_SETTINGS,
compactLegacySidebarStatuses: true,
+ showThreadWorktreeIndicators: false,
legacySidebarScale: 75,
roundedProjectIcons: true,
environmentIconColors: { primary: "#2563eb", remote: "#7c3aed" },
@@ -218,6 +220,7 @@ describe("LastCodeSettingsImport", () => {
);
assert.equal(importedClient.fontSizeInterface, 17);
assert.equal(importedClient.compactLegacySidebarStatuses, true);
+ assert.equal(importedClient.showThreadWorktreeIndicators, false);
assert.equal(importedClient.legacySidebarScale, 75);
assert.equal(importedClient.roundedProjectIcons, true);
assert.deepEqual(importedClient.environmentIconColors, {
diff --git a/apps/desktop/src/settings/LastCodeSettingsImport.ts b/apps/desktop/src/settings/LastCodeSettingsImport.ts
index 806b227f9564..0a1cf69d9b15 100644
--- a/apps/desktop/src/settings/LastCodeSettingsImport.ts
+++ b/apps/desktop/src/settings/LastCodeSettingsImport.ts
@@ -241,6 +241,7 @@ function mergeClientSettings(sourceRaw: string, destinationRaw: string | null):
legacySidebarScale: destination.legacySidebarScale,
roundedProjectIcons: destination.roundedProjectIcons,
showLocalEnvironmentIcon: destination.showLocalEnvironmentIcon,
+ showThreadWorktreeIndicators: destination.showThreadWorktreeIndicators,
})}\n`;
}
diff --git a/apps/web/src/components/LegacySidebar.tsx b/apps/web/src/components/LegacySidebar.tsx
index 45172ea581c8..04315e7b61d4 100644
--- a/apps/web/src/components/LegacySidebar.tsx
+++ b/apps/web/src/components/LegacySidebar.tsx
@@ -341,6 +341,7 @@ function buildThreadJumpLabelMap(input: {
interface SidebarThreadRowProps {
thread: SidebarThreadSummary;
compactStatusIndicators: boolean;
+ showWorktreeIndicators: boolean;
showLocalEnvironmentIcon: boolean;
configuredEnvironmentIconColor: EnvironmentIconColor | undefined;
projectCwd: string | null;
@@ -934,7 +935,7 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr
)}
-
+ {props.showWorktreeIndicators ? : null}
{terminalStatus && (
>;
environmentIconColors: Readonly>;
@@ -1206,6 +1208,7 @@ const SidebarProjectThreadList = memo(function SidebarProjectThreadList(
const {
legacySidebarScale,
compactStatusIndicators,
+ showWorktreeIndicators,
scaleStyle,
providerEntriesByEnvironmentId,
environmentIconColors,
@@ -1277,6 +1280,7 @@ const SidebarProjectThreadList = memo(function SidebarProjectThreadList(
key={threadKey}
thread={thread}
compactStatusIndicators={compactStatusIndicators}
+ showWorktreeIndicators={showWorktreeIndicators}
showLocalEnvironmentIcon={showLocalEnvironmentIcon}
configuredEnvironmentIconColor={environmentIconColors[thread.environmentId]}
projectCwd={projectCwd}
@@ -1351,6 +1355,7 @@ const SidebarProjectThreadList = memo(function SidebarProjectThreadList(
interface SidebarProjectItemProps {
legacySidebarScale: LegacySidebarScale;
compactStatusIndicators: boolean;
+ showWorktreeIndicators: boolean;
scaleStyle: CSSProperties;
providerEntriesByEnvironmentId: ReadonlyMap>;
desktopLocalEnvironmentIds: ReadonlySet;
@@ -1380,6 +1385,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
const {
legacySidebarScale,
compactStatusIndicators,
+ showWorktreeIndicators,
scaleStyle,
providerEntriesByEnvironmentId,
project,
@@ -2764,6 +2770,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
>;
desktopLocalEnvironmentIds: ReadonlySet;
@@ -3339,6 +3347,7 @@ const SidebarProjectsContent = memo(function SidebarProjectsContent(
projectsLength,
legacySidebarScale,
compactStatusIndicators,
+ showWorktreeIndicators,
projectTreeScaleStyle,
providerEntriesByEnvironmentId,
desktopLocalEnvironmentIds,
@@ -3473,6 +3482,7 @@ const SidebarProjectsContent = memo(function SidebarProjectsContent(
settings.compactLegacySidebarStatuses,
);
+ const showWorktreeIndicators = useClientSettings(
+ (settings) => settings.showThreadWorktreeIndicators,
+ );
const environmentIconColors = useClientSettings((s) => s.environmentIconColors);
const showLocalEnvironmentIcon = useClientSettings((s) => s.showLocalEnvironmentIcon);
const serverProviders = useAtomValue(primaryServerProvidersAtom);
@@ -4264,6 +4278,7 @@ export default function LegacySidebar() {
projectsLength={projects.length}
legacySidebarScale={legacySidebarScale}
compactStatusIndicators={compactStatusIndicators}
+ showWorktreeIndicators={showWorktreeIndicators}
projectTreeScaleStyle={scaleStyle}
providerEntriesByEnvironmentId={providerEntriesByEnvironmentId}
desktopLocalEnvironmentIds={desktopLocalEnvironmentIds}
diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx
index 48ec1c759c06..1f4dfb63757a 100644
--- a/apps/web/src/components/Sidebar.tsx
+++ b/apps/web/src/components/Sidebar.tsx
@@ -627,6 +627,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
environmentLabel: string | null;
environmentKnown: boolean;
showLocalEnvironmentIcon: boolean;
+ showWorktreeIndicators: boolean;
configuredEnvironmentIconColor: EnvironmentIconColor | undefined;
projectCwd: string | null;
projectFaviconPath: string | null;
@@ -1606,7 +1607,9 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
branch, so the row lost its most stable identifier. */}
{thread.branch ? (
<>
-
+ {props.showWorktreeIndicators ? (
+
+ ) : null}
{thread.branch}
>
) : (
@@ -1808,6 +1811,7 @@ export default function Sidebar() {
const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings);
const environmentIconColors = useClientSettings((s) => s.environmentIconColors);
const showLocalEnvironmentIcon = useClientSettings((s) => s.showLocalEnvironmentIcon);
+ const showWorktreeIndicators = useClientSettings((s) => s.showThreadWorktreeIndicators);
const {
settleThread,
unsettleThread,
@@ -3859,6 +3863,7 @@ export default function Sidebar() {
environmentLabel={environmentLabelById.get(thread.environmentId) ?? null}
environmentKnown={environmentLabelById.has(thread.environmentId)}
showLocalEnvironmentIcon={showLocalEnvironmentIcon}
+ showWorktreeIndicators={showWorktreeIndicators}
configuredEnvironmentIconColor={environmentIconColors[thread.environmentId]}
projectCwd={
projectCwdByKey.get(`${thread.environmentId}:${thread.projectId}`) ?? null
diff --git a/apps/web/src/components/settings/LastCodeSettings.tsx b/apps/web/src/components/settings/LastCodeSettings.tsx
index c083c65d5291..cb8e80beb58c 100644
--- a/apps/web/src/components/settings/LastCodeSettings.tsx
+++ b/apps/web/src/components/settings/LastCodeSettings.tsx
@@ -247,6 +247,19 @@ export function LastCodeSettingsPanel() {
/>
}
/>
+
+ updateClientSettings({ showThreadWorktreeIndicators: Boolean(checked) })
+ }
+ aria-label="Show worktree indicators"
+ />
+ }
+ />
{
expect(searchSettings("compact status").map((item) => item.id)).toEqual([
"compact-status-indicators",
]);
+ expect(searchSettings("worktree indicators").map((item) => item.id)).toEqual([
+ "show-worktree-indicators",
+ ]);
expect(searchSettings("xyzzy")).toEqual([]);
});
diff --git a/apps/web/src/components/settings/settingsSearch.ts b/apps/web/src/components/settings/settingsSearch.ts
index 1d94858750c9..5e4cf898e4f0 100644
--- a/apps/web/src/components/settings/settingsSearch.ts
+++ b/apps/web/src/components/settings/settingsSearch.ts
@@ -265,6 +265,11 @@ export const SETTINGS_SEARCH_ITEMS = [
title: "Compact status indicators",
to: "/settings/lastcode",
},
+ {
+ id: "show-worktree-indicators",
+ title: "Show worktree indicators",
+ to: "/settings/lastcode",
+ },
{
id: "rounded-project-icons",
title: "Rounded project icons",
diff --git a/docs/user/thread-sidebar.md b/docs/user/thread-sidebar.md
index 955387a97216..f68aad0dcefc 100644
--- a/docs/user/thread-sidebar.md
+++ b/docs/user/thread-sidebar.md
@@ -70,6 +70,9 @@ indicators** in **Settings -> LastCode -> Appearance**. Legacy thread rows then
colored status dot; the full status remains available as a tooltip. This preference is off by
default.
+To hide the worktree icon beside threads that use a dedicated worktree, turn off **Show worktree
+indicators** in **Settings -> LastCode -> Appearance**. The icon remains visible by default.
+
## Environment icons in LastCode
Open **Settings -> LastCode -> Environments** to choose the icon color for the primary machine and
diff --git a/packages/contracts/src/settings.test.ts b/packages/contracts/src/settings.test.ts
index a93d564b40ab..233148d87830 100644
--- a/packages/contracts/src/settings.test.ts
+++ b/packages/contracts/src/settings.test.ts
@@ -116,6 +116,7 @@ describe("ClientSettings sidebar", () => {
it("defaults to the current sidebar with automatic merge and inactivity settling", () => {
const settings = decodeClientSettings({});
expect(settings.compactLegacySidebarStatuses).toBe(false);
+ expect(settings.showThreadWorktreeIndicators).toBe(true);
expect(settings.legacySidebarEnabled).toBe(false);
expect(settings.legacySidebarScale).toBe(100);
expect(settings.sidebarAutoSettleAfterDays).toBe(3);
@@ -149,6 +150,16 @@ describe("ClientSettings sidebar", () => {
).toBe(true);
});
+ it("preserves an explicit worktree indicator preference", () => {
+ expect(
+ decodeClientSettings({ showThreadWorktreeIndicators: false }).showThreadWorktreeIndicators,
+ ).toBe(false);
+ expect(
+ decodeClientSettingsPatch({ showThreadWorktreeIndicators: false })
+ .showThreadWorktreeIndicators,
+ ).toBe(false);
+ });
+
it.each([50, 75, 100])("accepts a legacy sidebar scale within 50..100: %s", (value) => {
expect(decodeClientSettings({ legacySidebarScale: value }).legacySidebarScale).toBe(value);
expect(decodeClientSettingsPatch({ legacySidebarScale: value }).legacySidebarScale).toBe(value);
diff --git a/packages/contracts/src/settings.ts b/packages/contracts/src/settings.ts
index aa09a5e6eb0b..4e690b9ed89f 100644
--- a/packages/contracts/src/settings.ts
+++ b/packages/contracts/src/settings.ts
@@ -184,6 +184,9 @@ export const ClientSettingsSchema = Schema.Struct({
compactLegacySidebarStatuses: Schema.Boolean.pipe(
Schema.withDecodingDefault(Effect.succeed(false)),
),
+ showThreadWorktreeIndicators: Schema.Boolean.pipe(
+ Schema.withDecodingDefault(Effect.succeed(true)),
+ ),
dismissedProviderUpdateNotificationKeys: Schema.Array(TrimmedNonEmptyString).pipe(
Schema.withDecodingDefault(Effect.succeed([])),
),
@@ -906,6 +909,7 @@ export const ClientSettingsPatch = Schema.Struct({
confirmThreadArchive: Schema.optionalKey(Schema.Boolean),
confirmThreadDelete: Schema.optionalKey(Schema.Boolean),
compactLegacySidebarStatuses: Schema.optionalKey(Schema.Boolean),
+ showThreadWorktreeIndicators: Schema.optionalKey(Schema.Boolean),
diffIgnoreWhitespace: Schema.optionalKey(Schema.Boolean),
environmentIdentificationMode: Schema.optionalKey(EnvironmentIdentificationMode),
environmentIconColors: Schema.optionalKey(Schema.Record(EnvironmentId, EnvironmentIconColor)),