You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Let me pin an automation so its latest workspace stays in the sidebar #6172
I run 13 scheduled automations on a 24/7 host (SEO monitors, a CWV fixer, weekly release notes). Every run mints a fresh workspace, which is exactly what I want for isolation. The problem is visibility: pinning works at the workspace level, so a pin points at yesterday's dead run by the next morning, and pinning every run would flood the sidebar with stale entries.
Ideally I'd pin the automation itself and the sidebar entry would always resolve to its newest workspace. One row per automation, always current. An "Automations" group in the sidebar would work too.
Current workaround is the Workspaces page filtered to the host. It works, but it mixes automation runs with everything else, and there's no pin control in the CLI or API to script around this.
This is a feature request, not a bug, and the code matches the described behavior exactly. Superset's sidebar pin is a property of a workspace, and an automation running in "fresh workspace per run" mode mints a new workspace id on every dispatch, so a pin made today is attached to a workspace that will never be reused tomorrow. There is currently no entity in the sidebar model that can represent "an automation, resolved to its newest run," and no CLI/API surface for pinning at all — the pin lives only in renderer-local state on one machine.
Affected code
Pinning is workspace-scoped, renderer-local state
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts:135 — sidebarState.pinnedAt (epoch ms, null = unpinned) on the per-workspace v2WorkspaceLocalState row. This is the only pin field in the app.
apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts:449 — setWorkspacePinned(workspaceId, projectId, pinned); keyed by workspace id.
.../DashboardSidebar/hooks/useDashboardSidebarData/buildDashboardSidebarProjects.ts:59 and :114 — partitionSidebarWorkspacesByPinned / buildDashboardSidebarPinnedWorkspaces, both typed over SidebarWorkspaceInput.
.../DashboardSidebar/types.ts:71 — the sidebar row union is { type: "workspace" } | { type: "section" }, and DashboardSidebarPinnedSection.tsx:45-55 renders DashboardSidebarWorkspaceItem only.
So "pin an automation" is not a flag flip; it needs a new pinnable row kind.
Why the pin goes stale by morning
packages/trpc/src/router/automation/dispatch.ts:127 — workspaceId = automation.v2WorkspaceId ?? (await createFreshWorkspace()). With fresh-per-run (v2WorkspaceId null), createWorkspaceOnHost (dispatch.ts:262-317) creates a brand-new workspace with a timestamped branch on every dispatch.
The new id is recorded on the run row, not the automation: packages/db/src/schema/schema.ts:826 (automation_runs.v2_workspace_id). Nothing ever repoints a pinnedAt from run N to run N+1.
apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/usePlaceLocalWorktreesInSidebar/usePlaceLocalWorktreesInSidebar.ts:12-23 places every automation-created worktree into the sidebar as a normal row. Worth noting for triage: with 13 automations on a 24/7 host the sidebar already accumulates one row per run regardless of pinning — the pin flooding described is a subset of a broader retention gap.
The existing near-miss (please don't close as already-supported)
automations.v2_workspace_id (packages/db/src/schema/schema.ts:780) is already called the pinned workspace in the dispatcher — see the stale-pin recovery at dispatch.ts:133-158 — and it's settable via superset automations create --workspace <id> (packages/cli/src/commands/automations/create/command.ts:26, "existing v2 workspace id — reuses it every run"). That does yield one stable sidebar row, but it achieves it by reusing a single worktree forever, which trades away exactly the per-run isolation this request wants to keep. The two are different features.
CLI/API pin control: confirmed absent
packages/cli/src/commands/workspaces/update/command.ts:9-14 accepts only --name, --task-id, --clear-task. Pin state never leaves the renderer's local collection, and as the hook doc at usePlaceLocalWorktreesInSidebar.ts:14-16 notes, the CLI and automations go through the host service and "can't write renderer-local sidebar state." A scriptable pin therefore needs a server-side home for the pin, not just a new CLI flag. This also interacts with the persisted-state policy in apps/desktop/AGENTS.md (entity-keyed state belongs in SQLite; cross-machine deletes bypass UI cleanup) — today a pin is silently per-machine.
Root cause
Not a defect. The pin's identity key is the workspace id, and fresh-per-run mode makes that key ephemeral by design. There is no automationId → newest workspace indirection anywhere in the sidebar data path.
Reproduction
superset automations create --project <projectId> --agent <agent> with a short rrule (no --workspace, so each run mints a workspace).
Let it dispatch twice.
Right-click run 1's workspace in the sidebar → Pin.
After run 2, the Pinned section still shows run 1's workspace; run 2 appears as a separate unpinned row under the project group.
A unit-level characterization test fits next to buildDashboardSidebarProjects.test.ts: feed two SidebarWorkspaceInput rows from the same automation (only the first with pinnedAt) and assert the pinned partition contains the older one — which documents that nothing maps an automation to its latest workspace.
Suggested direction
The building block already exists: automation.listRuns (packages/trpc/src/router/automation/automation.ts:589-605) orders desc(automationRuns.createdAt) and returns v2WorkspaceId plus terminalSessionId/chatSessionId, backed by automation_runs_history_idx. The automation detail page already performs exactly the resolve-and-navigate this request wants, at PreviousRunsList.tsx:48-59.
Option A — dynamic pin. Store pinned automation ids in a small singleton local collection, resolve each via listRuns({ limit: 1 }), and render it through the existing workspace item with the automation's name as the label. Requires a new row kind in types.ts, a builder beside buildDashboardSidebarPinnedWorkspaces, and care that the resolved workspace is excluded from its project group so it doesn't double-render (the same invariant partitionSidebarWorkspacesByPinned maintains today).
Option B — "Automations" group (the alternative in the request, and likely cleaner). A top-level section fed by automation.list, each row deep-linking to the newest run. This leaves pin semantics untouched, which matters because pinning is both workspace-scoped and machine-local.
Companion fix either way: add retention/auto-hide for older automation worktrees in selectWorktreesToPlace, or one stable row will still sit above N stale ones.
For scripting: exposing the resolved newest workspace read-only (e.g. on automations get) is purely additive over listRuns and could ship independently of any pin write path.
Perhaps an automation group works best, we would need to be able to affect sidebar state from host service which shouldn't be crazy lift. I also run a ton of automations so having automations automatically add itself to a group makes sense
An automations group that self-populates would be exactly it. Two things would round it out: older run workspaces auto-hiding once a newer one lands (the retention gap the bot flagged), and the newest workspace id readable on automations get so the CLI can script against it. Happy to test a build.
Adding a piece to the automations-group direction: an unread badge, so the group works as an inbox rather than just a folder.
Today every run lands as a normal sidebar row with no signal, so a new run is indistinguishable from thirty stale ones until I read each name. What would make the group usable at a glance:
The Automations group row shows an unread count (like a chat badge — "12 new runs since I last looked")
Opening or acting on a run marks it read and decrements the count; a "mark all read" on the group clears it in one action
Optionally per-automation counts inside the group
This also addresses the broader annoyance behind my original report: I want every workspace — user- or automation-initiated — in the sidebar by default. Today some runs end up unlisted, and the only way to find them is the Workspaces page, filtering, and manually pinning each one. A self-populating group with a badge makes new runs instantly visible and old ones dismissible in bulk, instead of one-by-one.
Activity
github-actions commentedon Aug 5, 2026
Summary
This is a feature request, not a bug, and the code matches the described behavior exactly. Superset's sidebar pin is a property of a workspace, and an automation running in "fresh workspace per run" mode mints a new workspace id on every dispatch, so a pin made today is attached to a workspace that will never be reused tomorrow. There is currently no entity in the sidebar model that can represent "an automation, resolved to its newest run," and no CLI/API surface for pinning at all — the pin lives only in renderer-local state on one machine.
Affected code
Pinning is workspace-scoped, renderer-local state
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts:135—sidebarState.pinnedAt(epoch ms,null= unpinned) on the per-workspacev2WorkspaceLocalStaterow. This is the only pin field in the app.apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts:449—setWorkspacePinned(workspaceId, projectId, pinned); keyed by workspace id..../DashboardSidebar/hooks/useDashboardSidebarData/buildDashboardSidebarProjects.ts:59and:114—partitionSidebarWorkspacesByPinned/buildDashboardSidebarPinnedWorkspaces, both typed overSidebarWorkspaceInput..../DashboardSidebar/types.ts:71— the sidebar row union is{ type: "workspace" } | { type: "section" }, andDashboardSidebarPinnedSection.tsx:45-55rendersDashboardSidebarWorkspaceItemonly.So "pin an automation" is not a flag flip; it needs a new pinnable row kind.
Why the pin goes stale by morning
packages/trpc/src/router/automation/dispatch.ts:127—workspaceId = automation.v2WorkspaceId ?? (await createFreshWorkspace()). With fresh-per-run (v2WorkspaceIdnull),createWorkspaceOnHost(dispatch.ts:262-317) creates a brand-new workspace with a timestamped branch on every dispatch.packages/db/src/schema/schema.ts:826(automation_runs.v2_workspace_id). Nothing ever repoints apinnedAtfrom run N to run N+1.apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/usePlaceLocalWorktreesInSidebar/usePlaceLocalWorktreesInSidebar.ts:12-23places every automation-created worktree into the sidebar as a normal row. Worth noting for triage: with 13 automations on a 24/7 host the sidebar already accumulates one row per run regardless of pinning — the pin flooding described is a subset of a broader retention gap.The existing near-miss (please don't close as already-supported)
automations.v2_workspace_id(packages/db/src/schema/schema.ts:780) is already called the pinned workspace in the dispatcher — see the stale-pin recovery atdispatch.ts:133-158— and it's settable viasuperset automations create --workspace <id>(packages/cli/src/commands/automations/create/command.ts:26, "existing v2 workspace id — reuses it every run"). That does yield one stable sidebar row, but it achieves it by reusing a single worktree forever, which trades away exactly the per-run isolation this request wants to keep. The two are different features.CLI/API pin control: confirmed absent
packages/cli/src/commands/workspaces/update/command.ts:9-14accepts only--name,--task-id,--clear-task. Pin state never leaves the renderer's local collection, and as the hook doc atusePlaceLocalWorktreesInSidebar.ts:14-16notes, the CLI and automations go through the host service and "can't write renderer-local sidebar state." A scriptable pin therefore needs a server-side home for the pin, not just a new CLI flag. This also interacts with the persisted-state policy inapps/desktop/AGENTS.md(entity-keyed state belongs in SQLite; cross-machine deletes bypass UI cleanup) — today a pin is silently per-machine.Root cause
Not a defect. The pin's identity key is the workspace id, and fresh-per-run mode makes that key ephemeral by design. There is no
automationId → newest workspaceindirection anywhere in the sidebar data path.Reproduction
superset automations create --project <projectId> --agent <agent>with a short rrule (no--workspace, so each run mints a workspace).A unit-level characterization test fits next to
buildDashboardSidebarProjects.test.ts: feed twoSidebarWorkspaceInputrows from the same automation (only the first withpinnedAt) and assert the pinned partition contains the older one — which documents that nothing maps an automation to its latest workspace.Suggested direction
The building block already exists:
automation.listRuns(packages/trpc/src/router/automation/automation.ts:589-605) ordersdesc(automationRuns.createdAt)and returnsv2WorkspaceIdplusterminalSessionId/chatSessionId, backed byautomation_runs_history_idx. The automation detail page already performs exactly the resolve-and-navigate this request wants, atPreviousRunsList.tsx:48-59.listRuns({ limit: 1 }), and render it through the existing workspace item with the automation's name as the label. Requires a new row kind intypes.ts, a builder besidebuildDashboardSidebarPinnedWorkspaces, and care that the resolved workspace is excluded from its project group so it doesn't double-render (the same invariantpartitionSidebarWorkspacesByPinnedmaintains today).automation.list, each row deep-linking to the newest run. This leaves pin semantics untouched, which matters because pinning is both workspace-scoped and machine-local.selectWorktreesToPlace, or one stable row will still sit above N stale ones.automations get) is purely additive overlistRunsand could ship independently of any pin write path.Kitenite commentedon Aug 5, 2026
Perhaps an automation group works best, we would need to be able to affect sidebar state from host service which shouldn't be crazy lift. I also run a ton of automations so having automations automatically add itself to a group makes sense
jaseemts commentedon Aug 5, 2026
An automations group that self-populates would be exactly it. Two things would round it out: older run workspaces auto-hiding once a newer one lands (the retention gap the bot flagged), and the newest workspace id readable on
automations getso the CLI can script against it. Happy to test a build.jaseemts commentedon Aug 29, 2026
Adding a piece to the automations-group direction: an unread badge, so the group works as an inbox rather than just a folder.
Today every run lands as a normal sidebar row with no signal, so a new run is indistinguishable from thirty stale ones until I read each name. What would make the group usable at a glance:
This also addresses the broader annoyance behind my original report: I want every workspace — user- or automation-initiated — in the sidebar by default. Today some runs end up unlisted, and the only way to find them is the Workspaces page, filtering, and manually pinning each one. A self-populating group with a badge makes new runs instantly visible and old ones dismissible in bulk, instead of one-by-one.