
Sessions Management
OfficialFreeEssential guidelines for agents window development.
Free · Opens the source repo
What Sessions Management does
The Sessions Management skill provides critical documentation for developers working on the agents window in Visual Studio Code. It outlines mandatory reading materials that must be reviewed before making any code changes within the src/vs/sessions/ directory. This includes coding guidelines, source code organization, and detailed specifications for various components of the agents window. By adhering to these guidelines, developers can ensure that their contributions are consistent and maintainable, ultimately enhancing the overall quality of the codebase.
The skill also includes a comprehensive set of specification documents that cover various aspects of the agents window architecture. These documents detail the internal layer hierarchy, layout specifications, session management, and mobile adaptations. Each specification is designed to guide developers through the complexities of the agents window, ensuring that they understand the required structure and behavior of the components they are working on. This structured approach helps in avoiding common pitfalls and ensures that all changes are well-documented and in sync with the corresponding specifications.
This skill is particularly useful for developers who are tasked with implementing new features or fixing issues related to the agents window. By following the provided guidelines and specifications, developers can streamline their workflow and reduce the likelihood of introducing errors. The skill serves as a valuable reference point, making it easier for developers to navigate the intricacies of the agents window architecture and collaborate effectively with their peers.
In summary, the Sessions Management skill is an essential resource for developers looking to contribute to the agents window in Visual Studio Code. It provides the necessary documentation and guidelines to ensure that their work aligns with the established standards and practices, ultimately leading to a more robust and reliable codebase.
When to use it
Use this skill when you are planning to implement features or fix issues in the agents window of Visual Studio Code.
When not to use it
This skill is not suitable for general coding tasks outside of the agents window context or for developers not working on Visual Studio Code.
What you can build with it
Implementing a New Feature
When adding a new feature to the agents window, refer to the specifications to ensure compliance with existing architecture.
Fixing a Bug
Use the guidelines to understand the structure of the agents window and address any issues effectively.
Collaborating with Team Members
Leverage the documentation to align your work with team standards and facilitate better collaboration.
How to install Sessions Management
View source1. Install with the skills CLI
npx skills add microsoft/vscode/sessions --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by microsoftBefore Making Any Changes
MANDATORY: Before writing or modifying any code in src/vs/sessions/, you must read these documents:
.github/instructions/coding-guidelines.instructions.md— Naming conventions, code style, string localization, disposable management, and DI patterns..github/instructions/source-code-organization.instructions.md— Layers, target environments, dependency injection, and folder structure conventions.
Then read the relevant spec for the area you are changing (see table below). If you modify the implementation, you must update the corresponding spec to keep it in sync.
Specification Documents
| Document | Path | When to read |
|---|---|---|
| Layer rules | src/vs/sessions/LAYERS.md | Before adding any cross-module imports. Defines the internal layer hierarchy (core → services → contrib → providers) with ESLint-enforced import restrictions. Key rule: contrib/* must NOT import from contrib/providers/*. |
| Layout spec | src/vs/sessions/LAYOUT.md | Before changing any part, grid structure, titlebar, or CSS. Documents the fixed grid layout (Sidebar | ChatBar | AuxiliaryBar), part positions, the modal editor system, per-session layout state persistence, and the titlebar's three-section design. |
| Layout controller spec | src/vs/sessions/LAYOUT_CONTROLLER.md | Before changing LayoutController or per-session layout state. Details how the auxiliary bar, panel, and editor working sets are captured/restored when switching sessions, multi-session suppression, the auto-reveal-on-changes flow, workspace-folder ordering, and storage/migration. |
| Sessions spec | src/vs/sessions/SESSIONS.md | Before changing session/provider interfaces or data flow. Covers the pluggable provider model (ISessionsProvider → ISessionsProvidersService → ISessionsManagementService), ISession/IChat interfaces, observable state propagation, workspace/folder model, and session type system. |
| Sessions list spec | src/vs/sessions/SESSIONS_LIST.md | Before changing the sessions sidebar list. Covers the tree widget (WorkbenchObjectTree), renderers, grouping (workspace/date), filtering (type/status/archived/read), pinning, read/unread state, workspace capping, mobile adaptations, storage keys, and registered actions. |
| Mobile spec | src/vs/sessions/MOBILE.md | Before adding any phone-specific UI. Covers the mobile part subclass architecture, viewport classification (phone < 640px), MobileTitlebarPart, drawer-based sidebar, MobilePickerSheet, view/action gating with IsPhoneLayoutContext, and the desktop → mobile component mapping. |
| AI Customizations | src/vs/sessions/AI_CUSTOMIZATIONS.md | Before working on the customization editor or tree view. Documents the management editor (in vs/workbench) and the tree view/overview (in vs/sessions/contrib/aiCustomizationTreeView). |
Common Pitfalls
-
Keep workspace fallback discovery out of the picker UI class: provider-session subscriptions, ranking, deduplication, and existence checks belong in a focused helper such as
SessionWorkspaceFallback. The picker should only enforce source priority, reject stale async results, and publish the selected workspace. -
Paired experiment treatments must resolve atomically: when a prompt and its editable placeholder are separate treatment values, use them only when both are non-empty; otherwise use both defaults so copy from different variants is never mixed. The prompt may omit the placeholder token entirely, in which case it is used literally and placeholder highlighting is simply absent.
-
Onboarding variations share structural steps and vary only their run step: keep one scenario for workspace selection, then resolve the experiment/developer variation when the run step executes. Personalized GitHub prompts use existing authentication silently, stay within a bounded cancellable lookup, verify that the selected draft workspace is still current, and fall back to the default prompt without surfacing an error.
-
Prompt-option headings and cards are one visual surface: group them with one enclosing border on the session surface; filling the entire group with the chat-input background makes it compete with the input, so reserve that fill for the cards. In each card, keep the icon and title on the first row, let supporting text span from the card's leading edge beneath the icon, and balance top/bottom padding so short copy does not leave a hollow corner.
-
GitHub prompt-option numbers belong with the action title: render labels such as "Tackle issue #123" or "Fix CI #456" on the first row and reserve the second row for the issue/PR title. This preserves the scarce full-width line for descriptive repository content.
-
Prompt-option selection has two generated input forms: the selected option stays switchable while the input is empty, exactly matches its full prompt, or exactly matches that prompt after its editable placeholder was activated and removed; every other edit disables the cards. Animate only the first insertion, replace later selections immediately, focus the input on activation, and use the card foreground for selected borders rather than conflating selection with the blue focus color.
-
Repository prompt options follow the draft workspace: keep a contribution-owned watcher after the onboarding run step completes. A workspace change clears stale cards immediately, shows loading skeletons, cancels the old lookup, and resolves a fresh bounded option set for the replacement draft; completed candidates from a timed-out lookup remain available only when their repository context is still current.
-
Prompt-option disabled presentation must not reuse Button's shared
.disabledopacity: the base rule is!important, so component-specific selected/disabled opacity cannot win without another forbidden override. Keep cards focusable, exposearia-disabled, gate activation in the component, and use a component-owned state class; gate skeleton animation with.monaco-reduce-motionso the effectiveworkbench.reduceMotionsetting wins over the OS media query. -
Ellipsized prompt-option copy needs an explicit full-content hover: register an
IHoverServicemanaged hover on every card and include both the complete action title and complete supporting text. Do not rely on clipped DOM text or a native title tooltip; GitHub titles routinely exceed the card width. -
Three prompt options must fill every row: render three equal growing cards on one row when space allows. At the two-column breakpoint keep
flex-growenabled so the third card occupies the full wrapped row instead of leaving an empty column. -
GitHub prompt-option numbers are secondary title metadata: model the issue/PR number separately from the action title, render it beside the title using the same muted color as the second line, and combine both only for ARIA and full-content hovers. Do not parse or color substrings inside one title string.
-
Agent-host onboarding readiness comes from advertised session types, not provider registration: an agent-host provider exists before its root state connects, while its
sessionTypesstay empty. Gate tours that need a usable host on a context key derived from anylocal-agent-host/agenthost-*provider exposing a session type, and update it fromISessionsManagementService.onDidChangeSessionTypes. -
Diagnostic log text is not a unit-test contract: add consistently prefixed, actionable logs, but do not add tests that assert log messages or levels. Validate the underlying behavior and keep diagnostics free to evolve.
-
Shared visual-module gates must not activate broader layout contracts: the Agents window may opt into shared editor-tab styles through a tab-specific root class, but must not apply the broad
style-overrideclass unless it also loads every matching Modern UI layout module. Keep shared tab runtime metrics aware of both gates, and preserve structural behavior such as a sticky add-tab action when removing a Sessions-owned stylesheet. Since the Agents workbench is always modern, chat-tab presentation belongs in the owningchatCompositeBar.css, scoped through.session-chat-tabs-barand chat-specific classes while consuming shared state tokens; do not add Sessions selectors to or rewrite the shared editor stylesheet. -
Minimum-size activation across the Sessions/Editor split must be symmetric and layout-aware: when either part is at minimum width, pointer or keyboard activation expands it by shrinking its sibling to minimum width. In single-pane layout, the Editor grid node's effective minimum includes the visible docked Auxiliary Bar width; using
editorPartView.minimumWidthalone collapses Details. -
Do not inject
ISessionsServiceinto editor-part construction: the sessions service depends on editor parts through the sessions-part graph, so injecting it intoSinglePaneMainEditorPartcauses recursive service instantiation during startup. Prefer lower-level services such asILabelServicewhen the editor only needs resource presentation. -
Workspace-folder labels must distinguish physical paths from repository identity: a worktree URI basename is the worktree directory, not the repository name. Route breadcrumb and workspace-projection labels through the delayed
IWorkspaceFolderLabelService; the Agents implementation may readISessionsService.activeSessionbecauseBreadcrumbsModelis created fromBreadcrumbsControl.update()after editor-part construction, but never injectISessionsServiceintoSinglePaneMainEditorPartitself. Breadcrumbs omit a workspace root whenever only one folder exists in any VS Code window; folder changes rebuild the model and recompute labels. -
Session repository labels come from
ISessionFolder.name, not the repository URI basename: providers may supply a richer display identity such asorg/repo. Use the session folder name for plain and verbose labels, and use URI basenames only as the final no-session fallback. -
Breadcrumb item equality must include presentation overrides:
BreadcrumbsWidget.setItemsretains equal prefix items, so a customFileElement.labelmust participate in equality. Otherwise folder or session-label changes for the same URI update the model but leave stale DOM text. -
Animation performance must preserve perceptual smoothness: reducing a continuous title shimmer to 10 stepped updates per second makes the sweep visibly choppy even if paint counts improve. Use a smooth baseline such as 30 updates per second, then measure the remaining performance win; do not optimize decorative motion by callback counts alone.
-
Pet placement must align the visible sprite, not only its absolute-positioning box: anchoring the button at
bottom: 100%leaves the pet visually detached because the input stack has top padding and transient confirmation/question surfaces add their own top margin. Keep the host on the complete stack and derive the optical offset from the actual input-to-host inset, capped at the confirmation/question alignment; one fixed deeper offset makes the bare input look overlapped. -
Keep only the rendering pet's speech bubble inside its input bounds without turning the pet around: the speech sprite's visible pixels overhang the button on the right, so dragging the rendering pet to the input's right edge can clip the ellipsis. Move the mirrored bubble fully to the pet's left with only its tail touching; do not center it over the pet, and do not apply the special treatment to yapping or any other state.
-
Do not conflate custom-agent selection with Agent Host execution mode:
chat.modeChangedescribes workbench mode/custom-agent picker selections, whileinteractive,plan, andautopilotare Agent Host execution modes and belong inagentHost.executionModeChanged. Preserve the SDK-native mode event as a peer rather than reshaping either axis into the other. -
Picker telemetry must use the scoped session and active chat: Agents Window action view items can belong to a non-active visible session or peer chat. Resolve previous selection and request counts from scoped
ISessionContext.session.activeChat, never a window-global picker model or parent session resource. -
Regrouping already-visible picker entries as enrichment arrives: grouped async pickers must append groups in their final order rather than initially showing fallback groups and moving entries later. Fetch the source set once, run small group-membership queries in parallel, then append each completed group in display order.
-
Viewer-group PR results and paged catalog results are one loaded set: search, deduplication, and re-rendering must use their union. Replacing picker items from catalog pages alone can make an already-visible matching review/assignment PR disappear.
-
Folder isolation is not worktree isolation:
isolationMode: 'workspace'means the ordinary folder mode and must not requiresupportsWorktreeConfiguration. Gate provider selection only for actual worktree settings. -
GitHub fork PR branches are not base-repository branches: use the base repository's checkoutable
refs/pull/<number>/headref (or equivalent head-repository identity/commit), never fetch the unqualified fork branch name fromorigin. -
PR-session exclusion must understand checkout refs: after using
refs/pull/<number>/head, older or partially hydrated sessions may only exposeorigin/pull/<number>/headas their upstream. Recover the PR number from that ref instead of comparing it only with the source branch name. -
Hidden queued requests stay hidden while pending: propagate transcript visibility onto the pending request model and filter hidden pending rows before adding queue dividers.
-
Creating a custom materialization path for a hidden bootstrap turn: use
ISessionsManagementService.createAndSendNewChatRequestwith the normal session options (includingworktreeBranchTrack) and mark the bootstrap request/response hidden from the transcript. Keep the turn in durable model history instead of inventing a second session-creation lifecycle. -
Showing local-worktree actions on cloud-only repository headers: a GitHub-backed section is not necessarily a usable checkout, while session-type capabilities register asynchronously and
file-only checks incorrectly exclude remote-host workspaces. Hide the action only forgithub-remote-filecloud sections, resolve within the originating section, and enforce provider capability when creation starts. -
Reading observable repository metadata once while rendering a section header: local workspace and GitHub metadata can hydrate after the tree template is created, leaving scoped menu context keys permanently false. Bind repository-derived header keys in an element-scoped
autorunand clear it whenever the recycled template changes elements. -
Requiring GitHub identity and a usable checkout on the same session folder: mixed workspace sections can carry repository identity on a cloud session while a separate local/remote-host session carries the checkout. Combine identity and non-cloud workspace presence at section scope, then resolve the non-cloud folder from that originating section.
-
Hiding repository actions when optional
gitHubInfois absent: some local providers intentionally leavegitHubInfoundefined even for GitHub clones. Gate only on a non-cloud workspace, then resolve identity lazily from session metadata or the checkout's ordered Git remotes when the action runs. -
Awaiting repository discovery before showing a picker: opening an unscanned checkout can take several seconds and makes the toolbar action appear inert. Show the picker immediately with a localized disabled/busy state, await repository/remotes hydration via observables, and cancel that wait when the picker closes.
-
Steering visible input into a hidden bootstrap turn: tools and confirmations produced after steering still belong to the hidden response, leaving the session in Needs Input without an actionable transcript row. Keep hidden bootstrap prompts tool-free and convert steering submissions to queued messages while the active request is hidden.
-
Rejecting a headless worktree create before late session types register: local Agent Host types can arrive after repository and PR selection, so a synchronous capability check produces a false "no provider" error. Keep the initiating picker busy and await
onDidChangeSessionTypeswithout a timeout, canceling from the picker lifecycle. -
Opening a provisional chat with a filtered bootstrap and no visible state: the chat looks empty even though model loading/materialization is active. Show a quiet, accessible transcript-level readiness status driven by model/request observables, and remove it deterministically when the hidden bootstrap completes or visible content appears.
-
Mirroring a child chat widget's model in the owning view: the view already owns the load reference while
ChatWidgetowns the active view model; a second model observable can drift during clear/rebind races. Derive view-only state fromChatWidget.onDidChangeViewModelandwidget.viewModel.model, while retaining only the disposable model reference needed for lifetime ownership. -
Exposing a chat widget's internal transcript element for caller-owned markup: raw DOM access couples consumers to private structure and bypasses widget visibility/layout invariants. Add a semantic widget operation such as
setTranscriptProgress(...)and keep creation, accessibility, and visibility state inside the widget. -
Keeping bootstrap context in a view-only side channel: context needed by the next request must use the normal attachment pipeline so it reaches provider history and survives restore. Attach it to the hidden bootstrap with
_metadescribing its transcript presentation, mirror it through a semantic widget API, and synchronously move the same entry into the first visible request before context capture. -
A sash element's
left/topis the hit-area edge, not the split boundary:SplitView.getSashPositionreturns the exact boundary after the preceding view, thenSash.layoutsubtracts half the sash size so the draggable element is centered on that boundary. Align the Sessions/Editor and bottom-Panel grid sash hit areas toagents.layout.floatingPanelGap; do not apply that token to independent geometry such as the Auxiliary Bar's leading padding. -
Wrong menu IDs: Never use
MenuId.*fromvs/platform/actionsfor Agents window UI. Always useMenus.*frombrowser/menus.ts. -
Editor-group header existence must not depend on an editor-provided scope: the group-level
showHeaderoption enables both header actions and header-hosted breadcrumbs; each menu item gates itself with an active-editorwhenclause. An editor's optionalscopedInstantiationServiceproperty only supplies context for evaluating those clauses, and breadcrumbs compose into the same fixed-height header row rather than creating a second persistent slot. -
The empty Files breadcrumb belongs to the editor area, not the docked detail: expose the session working directory as the empty Files input's breadcrumb resource only while the editor area is visible. A detail-only layout may keep header actions visible, but it must not show a root breadcrumb for hidden editor content; preserve the underlying resource separately for serialization and refresh breadcrumbs from the editor-part visibility signal.
-
Pass the complete session workspace to the empty Files input, not a preselected folder URI: the input currently derives the first mounted working directory as its breadcrumb resource at one documented fallback point. A complete multi-root design can then change that input-owned decision to a workspace-level breadcrumb that identifies the workspace and exposes all roots, without rewiring every caller.
-
A superseded managed-tab reconcile must not publish input state after an await: foreign-editor cleanup can yield while a newer session queues a successor reconcile. Check the reconcile generation immediately after cleanup and before updating the retained Files input's workspace, so only the current reconcile can publish breadcrumbs.
-
Editor-header DOM must mirror its visual groups: breadcrumbs are a direct child of the header and a sibling of one actions container; that actions container directly owns the primary and secondary action hosts. Create the actions container and its hosts inside the
showHeaderconstruction branch, then attach it after breadcrumbs so ownership and DOM order stay explicit. -
Editor-header state belongs to the owned nodes and widgets, not their parent or CSS marker classes: do not add placement/state classes to the title parent, branch layout on the
showHeaderoption after construction, or infer action presence fromhas-no-actions. Use the created header element to distinguish placement andMenuWorkbenchToolBar.getItemsLength()to derive visibility; the toolbar may still set its internal compatibility class, but header logic and styling must not depend on it. -
Secondary editor-header actions need a structural trailing column: custom secondary view items can stretch their host, so
margin-left: autoplus content-sized flex is not sufficient. Use an actions grid with a flexible leading column and explicit secondary/separator/layout columns so secondary-only states remain trailing regardless of child sizing. -
Breadcrumbs and editor-header actions share an edge, not a parent gap: do not add
column-gapto the header row; it creates a visible hole between the flexed breadcrumb box and actions box. Breadcrumb content owns its trailing breathing room, while the two sibling containers remain contiguous. -
Header actions must not retain an empty leading grid track beside breadcrumbs: when breadcrumbs are visible, make the actions grid content-sized with auto columns; otherwise its flexible primary column becomes a visible hole inside the actions element. Only use the full-width
1frprimary column when breadcrumbs are absent, where it keeps primary actions left-anchored and secondary/layout actions trailing. -
Header breadcrumb layout measures the control, not its padded wrapper:
.breadcrumbs-below-tabshas Sessions-owned left padding, andclientWidthincludes that padding. PassbreadcrumbsControl.domNode.clientWidthtoBreadcrumbsControl.layout()so the widget receives its actual usable width and does not overrun or clip its trailing scroll range. -
Header-hosted breadcrumbs inherit the shared header background: the breadcrumb widget generates a light-theme background on its inner
.monaco-breadcrumbssurface, which contrasts with the editor-header tab background inherited by sibling actions. Override both the control and inner widget surface to transparent in the Sessions-scoped header breadcrumb stylesheet so the entire row uses one theme-owned surface color. -
Single-tab titles and the Sessions header are separate, aligned rows:
SingleEditorTabsControlrenders directly into the flex title parent, unlike the multi-tab control's nested strip. In the single-pane layout, allow that parent to wrap, giveEditorHeaderControla full-row flex basis and the bottom separator, align the title label to the header content inset, and order editor actions → Add Tab toolbar (with the toolbar'strailingSeparator) → layout actions. Do not hand-style a sibling separator. WhenevershowHeaderis enabled, breadcrumbs live only in that header for every tab mode; do not retain the single-title inline breadcrumb. Since other tabs are hidden, Add Tab shows every supported editor type even when already open; multi-tab mode keeps the missing-tab filter. -
A single-tab title must not repeat the header breadcrumb as its description: when
showHeadermoves breadcrumb ownership toEditorHeaderControl, render only the editor name inSingleEditorTabsControl. Falling back toeditor.getDescription(...)duplicates the same path above the breadcrumb row even though only one breadcrumb widget exists. -
Header breadcrumb ownership must not alter normal VS Code single-tab mode:
EditorHeaderControlcreates the single-tab breadcrumb only whenshowHeaderis explicitly enabled. Without a header, preserve the existingSingleEditorTabsControlinline breadcrumb and do not create a second control in the shared title parent. -
The single-pane Agents editor supports only single or multiple tabs: while
workbench.editor.showTabsis'none', hold a Sessions-ownedenforcePartOptions({ showTabs: 'single' })disposable; clear it for every other value. Do not add a shared editor-part normalization hook or force one mode unconditionally; explicitsingleandmultiplechoices, including live updates, must remain respected. -
Auxiliary-Bar-only composition always uses multiple tabs: when the docked Auxiliary Bar is visible and the editor area is hidden, the Sessions-owned tab override enforces
multipleregardless of the configured mode. Recompute the override from both relevant part-visibility events; when the editor returns, restore the configuredsingle/multiplebehavior (or thenone→singlefallback). -
Hidden header widgets must collapse their parent box: hiding only an inner control leaves the stable parent with its previous inline width, which can push sibling header actions to the right. Mirror visibility onto the parent container and define the common row height on the shared header, not on one child widget, so Changes actions and file breadcrumbs align without stale geometry.
-
An empty editor-group header must collapse completely: keep the stable header content hidden by default and show it only when breadcrumbs are visible or a primary/secondary menu host has actions. Hiding only the children can leave the header border or reserved height visible as an empty row.
-
Title content spans the full editor-group width: breadcrumbs and tabs use the full group width in every layout. Only the editor pane is narrowed beside the docked detail panel; do not thread the editor content inset through
EditorTitleControl.layout(). -
Agents header styling must not modify shared editor CSS: keep
vs/workbencheditor styles byte-for-byte unchanged so normal VS Code windows cannot regress. Add an explicit header-placement class in shared DOM code, then put every visual override under a Sessions-owned stylesheet scoped to.agent-sessions-workbench.dock-detail-panel. -
Header presentation has its own control:
EditorGroupViewpassesmenuIdsandshowHeadertoEditorTitleControl, which createsEditorHeaderControlwhen enabled.EditorHeaderControlowns header DOM, breadcrumbs, menu toolbars, scoped action rendering, visibility, and fixed height;EditorTitleControlowns tabs and includes the header height in its total. -
The title-owned header is a child of the title container and follows its recreate lifecycle: create it after the tabs inside
EditorTitleControl.parent, include its height in the title control's layout result, and rebuild it with tabs/breadcrumbs afterclearNode(parent)when editor options change. Do not make it a sibling that requires separate DOM cleanup and duplicate group layout subtraction. -
Header visibility updates distinguish creation from live changes:
updateHeaderVisibility(relayout)updates DOM/state in both cases, but creation and option-driven reconstruction passfalsebecause their caller already owns layout. Live menu-item and breadcrumb changes passtrueso the parent group is explicitly relaid out. -
Durable chat source/origin references: Store only
turnIdin durable fork/side-chat references. Active versus historical is mutable lifecycle state that consumers must resolve against the currentactiveTurnand retainedturnswhen needed; do not encode lifecycle state in the reference type. -
Selected side-chat text is an immutable snapshot, not a live range:
SideChatSource.selection/ChatOrigin.selectionpreserve the exact text captured at side-chat creation time. Never model it as offsets into the source transcript or try to recompute it from later DOM/protocol state. -
ChatSourceis fully discriminated: Fork and side-chat sources both require explicitkindplus stable top-levelturnId. Do not add no-kind compatibility helpers or route by structural property presence; switch directly onsource.kind. -
Sessions menu ids must live in the shared menu registry: Do not declare sessions-owned
new MenuId(...)constants ad hoc inside individual parts. Add them tobrowser/menus.tsunderMenuswith discoverableSessionsEditor...names so ownership and reuse stay obvious. -
Events instead of observables: Session state must flow through
IObservable, notEvent. Useautorun/derivedfor reactive UI, notonDid*event listeners. -
Importing from providers: Non-provider
contrib/*code must never import fromcontrib/providers/*. Extract shared interfaces toservices/orcommon/. -
IAgentSessionsServicein shared code:IAgentSessionsService(vs/workbench/contrib/chat/browser/agentSessions/agentSessionsService) is a Copilot-provider internal and may be imported only by the Copilot chat sessions provider (contrib/providers/copilotChatSessions/). Shared sessions code (core/services/non-provider contribs, e.g. the sessions list or visible-sessions grid) must stay provider-agnostic and go throughISession/ISessionsManagementService— never reach intomodel.observeSession(...)etc. for lazy loading. This is enforced by an ESLintno-restricted-importsban scoped tosrc/vs/sessions/**(Copilot provider exempted). -
Missing entry point import: New contribution files must be imported in the appropriate
sessions.*.main.tsentry point to be loaded (for examplesessions.common.main.ts,sessions.desktop.main.ts,sessions.web.main.ts, orsessions.web.main.internal.ts). -
Modifying workbench code: Prefer extending/wrapping workbench classes in the sessions layer over modifying shared workbench components.
-
Do not repeat subagent identity beside the open-chat pill: The subagent pill's title is the complete inline affordance. Do not render the agent name or a generic "Subagent" phrase before it; that duplicates identity and adds visual noise.
-
Subagent model metadata is differential inline, but complete in the hover: Show the subagent's model beside the pill by default and hide it only when it concretely matches the parent chat's selected model. Compare canonical ids, registered display names, and the parent input's selected-model metadata (active turns may not yet expose resolved response metadata). Keep the unfiltered subagent model in the hover/ARIA label regardless of inline visibility; if the parent model is unresolved, still show it inline because no match can be established.
-
Optional metadata owns its separator: Keep separators such as
·on the conditional metadata element and create that element hidden. An empty optional label must never leave punctuation behind while its reactive visibility is still resolving. -
Live numeric labels must not jitter: Apply
font-variant-numeric: tabular-numswithfont-feature-settings: "tnum"as a fallback to elapsed-time and other numeric labels that update in place. -
Collapsed work summaries must quantify what they hide: Prefer outcome-oriented copy such as "Completed 6 steps in 2m" over vague elapsed-only text such as "Worked for a few minutes." Count the visible items placed inside the disclosure so the summary matches what expanding it reveals.
-
Created-session result pills belong with the final response, not the collapsed work steps: A completed
create_session/create_chatpill is a durable outcome and navigation affordance. Render it only once the response completes and order it after the final response markdown, so it stays visible beside the completed-turn adjuncts without being repositioned while focused. -
Logical final markdown is not necessarily rendered final markdown: With incremental rendering, response completion accelerates the buffer but does not synchronously drain it to the DOM. Delay completed-work disclosure and bottom-summary placement until the final markdown part reports that its morpher has drained, then retry from that signal.
-
Custom action proxies must propagate owner-observed state: When an action view wraps a menu action in a proxy, state that controls surrounding UI (such as enabled/available) must also be written to the original menu action observed by the owner. Re-subscribe on
IActionViewItemService.onDidChangefor late factory registration, but do not assume the replacement proxy's state automatically reaches the menu action. -
Editor feedback glyph placement: Use Monaco's
lineNumberClassNamewhen the feedback affordance should replace the number only while its line is hovered; it eliminates a dedicated glyph lane while preserving the number at rest. Style the line-number pseudo-element as the full feedback control, including its themed hover background, so its visual and click target match. -
Line-number decoration tooltips belong in Monaco decoration options: A
lineNumberClassNamenode is regenerated as the editor renders and scrolls, so DOM-managed hovers can silently attach to a stale or never-decorated element. Set the localizedlineNumberHoverMessagewith the same decoration instead; Monaco's glyph hover controller follows the rendered line-number lifecycle. -
Compact multi-diff control alignment: The file-header twistie, unchanged-region expand control, and fold control form one visual column in the Agents editor. Remove the header content's left padding and use the same small inset for both unchanged-region controls; do not let the shared multi-diff defaults leave each control at a separate horizontal offset.
-
Embedded multi-diff gutters need a shared minimum width: Each embedded editor otherwise sizes line numbers from its own largest line number, causing the content and nearby feedback glyph to appear to drift between file entries. Set a common
lineNumbersMinCharswidth for the compact multi-diff; it remains stable through three-digit line numbers and grows only when a file exceeds that reserved capacity. -
Editor-content overlays must anchor to the inset pane, not the full editor group: In single-pane mode the editor group spans both the editor and docked detail panel, while
EditorGroupView.editorPaneContainerbounds only the editor content. Mount submit/navigation overlays to that pane container so their bottom-right position stays inside the diff when the detail panel is visible or resized. -
Timeouts as fixes: Never use
setTimeout/disposableTimeout/arbitrary delays to fix bugs or implement behaviour. They are race-prone guesses that mask the real ordering/state problem. Drive logic off deterministic signals instead — observables (autorun/derived), explicit events (onDidChange*), lifecycle phases, or awaiting the actual async operation. -
The prompt timeline dock treats the bottom as the latest prompt and pairs both hover directions: when the transcript is fully scrolled down, resolve the final prompt directly rather than scanning every prompt's top offset. Hovering either a dot or its prompt row must preview both elements; when the dots are capped, map the row to the nearest sampled dot.
-
Sticky prompt navigation must match the rail/title reveal: Previous/Next and the sticky title must all reveal the prompt (request) row aligned to the top via the shared
reveal(requestId)— the same path the dock/ruler rail uses. Do not align the following response to keep the header pinned, and do not add a "navigation pin" that forces the header to stay visible after a jump: the header is atop:0overlay, so it would cover the freshly top-aligned prompt (the prompt shows only a sliver). Let the header follow scroll tracking (it hides once the prompt is at the top), consistent with the dock. Use the chat request-bubble hover background (--vscode-chat-requestBubbleHoverBackground, toolbar hover as fallback), composited over the opaque panel base, for the sticky title affordance rather than an underline. -
Sticky prompt header transition is a label roll, not a moving band: on prompt change the label text rolls (WAAPI slide+fade of absolutely-positioned line elements inside an
overflow:hiddenclip viewport), while the opaque band stays fixed. Do NOT translate the whole band to get an Explorer-style push-off: the band would move above the transcript top (its container.interactive-sessionisoverflow:visible, so it'd overlap the session header) and clipping it would cut the band's soft drop-shadow. The roll gives the "header gives way to the next" feel with none of that risk. Gate the roll on the header already being visible (snap on first appearance/jumps) and honorprefers-reduced-motion. -
Sticky prompt header must mirror the session header's box model, not the message column: the band lives in a two-level structure — an outer full-width
.prompt-timeline-sticky(positioning + reveal only), a.prompt-timeline-sticky-contentcentered host (max-width: 950px; margin: 0 auto; padding: 0 10px, matching.session-view-centered-content+.chat-composite-bar.session-header-bar's 10px side padding), and an inner.prompt-timeline-sticky-band(flex: 1) that carries the background/border/shadow (mirroring.chat-composite-bar-header). This makes the band's background align exactly with the session header's bottom-border line above it. Do NOT paint the background on the full-width outer (bleeds past the header and over the scrollbar gutter — a ~1px right-edge "bump") or on the 950 message column (20px wider than the header, since the header is inset 10px). The band'spadding-left: 22px(16px icon + 6px gap) reproduces the header's status-icon column so the prompt text lines up with the title and the 32px-inset prompts below. -
Grid
onDidChangeis not a sash-drag signal: the workbenchSerializableGrid/GridViewonDidChangefires for size changes and view add/remove, but not internal splitview sash drags. If logic must react to a part node being resized by a sash, route it through that part'slayout(width, ...)callback, which receives the in-progress node width. -
Docked detail collapse must use the raw sash width before clamping: the docked auxiliary bar keeps a minimum visible width, so checking the clamped width can never detect a drag-to-zero collapse. Decide collapse from the raw requested sash width, then route the hide through
setPartHidden(AUXILIARYBAR_PART)so context keys and per-session capture stay in sync. -
Stashed state read back later (side-channels): Never stash a value on a service during one method call and read it back from a separate query later, assuming it is still valid (e.g. a
Set/flag set inopenSessionand consumed by ashouldX()pull-API). This is fragile temporal coupling. Instead, make it reactive state that is set atomically together with its source of truth and consumed reactively. Example: per-activation intent like "open in background / preserve focus" is exposed as anIObservableset in the same transaction asactiveSession(via a single internal setter so it can never go stale), and read with.read(reader)in the consumer'sautorun— never via a consume-once getter. -
Provider-owned model/mode selection belongs in the loaded chat model, with draft persistence driven by debounce: For AHP-backed chats,
setModel/setAgentmust push the selection into the loadedIChatModel.inputModel(like_updateChatSessionState) and let the draft-sync debounce emitchat/draftChanged. Do not immediately dispatch a model/agent-only draft from the provider, because it can overwrite unsaved typed text before the debounced full input-state draft is persisted. -
Blocking on a "pending/waiting" state instead of creating + upgrading: When an entity (e.g. a draft session) depends on something that registers asynchronously, don't withhold creation behind a pending/waiting state. Prefer creating immediately with the best available data, then replace/upgrade it once the awaited dependency arrives (driven by an
onDidChange*/observable signal), cancelling the upgrade if the user changes the inputs meanwhile. Do not bound the upgrade with a timeout or even a lifecycle milestone likeLifecyclePhase.Eventually— an agent host connects lazily and can surface its session types arbitrarily late, which would lock in the wrong fallback. Let the upgrade listener live for the consumer's lifetime instead. -
Over-commenting: Don't write long explanatory comments narrating what the code does or justifying ordinary patterns. Hard rules: JSDoc = 1–2 short sentences max (never enumerate every branch/feature, restate the signature, or list what the function does NOT do); inline method comments = 1 line max, only for a genuine workaround/non-obvious constraint, never to narrate the next statement. Default to no comment — if code needs a paragraph to explain, rename/extract instead. Before writing any comment longer than one line, delete it or shorten it to one line.
-
Inserting/removing DOM on demand for transient UI (e.g. inline rename inputs): Don't
insertBefore/appendChild+remove()a widget on the tab/row element itself when an interaction starts/ends — that churns the parent's child list and depends on event ordering during teardown. Also don't eagerly build a heavy widget (e.g. anInputBox) per row "just in case", since most rows never use it. Instead, create a stable, empty container alongside the label once, toggle its visibility via a CSS class on the row (e.g..editing), and create the widget inside that container lazily only while editing — disposing it and emptying the container (reset(container)) when done (InputBox.dispose()does not detach its own node). Prefer the shared themed widget (InputBox+defaultInputBoxStyles) over a hand-rolled<input>. -
Collapsing distinct provider identities in pickers: Do not collapse extension-backed chat session ids (e.g.
copilotcli) and agent-host ids (e.g.agent-host-copilotcli) based only on friendly names or well-known provider enums. They can coexist in the Agents window and route to different infrastructure; keep the exact session type id through selection/delegation and hide ambiguous legacy targets when an agent-host target supersedes them. -
Permission picker copy must stay provider-neutral and aligned: Reuse the same labels and descriptions across Copilot Chat and Agent Host permission pickers. Avoid provider-specific phrasing such as "Copilot uses..." when the same choice appears in the Agents window.
-
Interactive tool denial must use the SDK's interactive-denial result, not a hard reject: In the Agent Host Copilot provider, a user choosing Skip must resolve the permission request with
denied-interactively-by-userso the SDK feeds the denial back to the model and continues the turn. Reserverejectfor abort, disposal, or requests that cannot be presented to the user; returning it for a renderer decision terminates the session turn. -
Internal Agents workspace in recent history: Collapse every internal
User/agent-sessions.code-workspacevariant into one canonical Agents Window entry. Recognize the reserved path across profile and worktree user-data directories, and make the single picker entry point at the current environment's Agents workspace. -
Resolving a session's provider via the create-only tracking map: On the agent host, resolve the owning provider for any per-session operation (createChat, disposeChat, sendMessage, …) through
AgentService._findProviderForSession, never the raw_sessionToProvidermap. That map is populated only bycreateSession, so a restored session (alive in the state manager after a host restart but never created in this process) is absent from it — a direct lookup throwsno provider for sessionand silently breaks the feature (e.g. Add Chat did nothing for restored sessions while messaging worked, because messaging already used the fallback)._findProviderForSessionfalls back to the session URI's scheme provider, which is what makes restored sessions work. -
Dispatching per-chat side-channel actions (agent/model) to the session URI: An agent-host session can own multiple peer chats, each with its own backend conversation (
CopilotAgent._chatSessions). Conversation side-channel actions likeSessionAgentChanged/SessionModelChangedmust be dispatched to the per-chat turn channel (_resolveTurnDispatchChannel, which carries achatIdfragment for peer chats), notsession.toString(). The session URI resolves to the session's default chat (_sessions), so dispatching there silently applies the change to the wrong conversation and an additional chat never sees the agent/model swap. The host must also forward thechatChannelthroughagentSideEffects.handleAction→changeAgent/changeModel, which apply it to_chatSessionswhen present. The protocol modelssummary.agent/summary.modelat session level only, so equality guards comparing against session summary are valid for the default chat but must be skipped for peer chats. -
Do not infer or fall back from a peer chat channel after progress was emitted: Agent progress signals for chat-scoped actions, especially tool-call readiness and permission requests, must be emitted with the exact
ahp-chat://...channel that owns the tool. Do not recover by scanning active turns, remappingChatToolCallConfirmed, or usingparseDefaultChatUri(...) ?? sessionUriinAgentSideEffects; malformed/misrouted chat channels should fail loudly so the producer or dispatch path is fixed.handleToolCallConfirmedand_toolCallAgentsmust use the chat channel URI containing the tool call; keying by the parent session URI makes confirmations miss the pending SDK request. -
Do not synthesize default chat URIs in the workbench handler:
AgentHostSessionHandlermust source the upstream default chat URI from hydratedSessionState.defaultChat/SessionState.chatsand store that mapping in its chat-resource-to-upstream-URI map. CallingbuildDefaultChatUri(session)in the handler assumes one server URI shape and hides protocol/provider bugs; dispatch turn lifecycle and pending/input actions through the mapped upstream chat URI instead. -
Opening a subagent editor must carry the exact upstream chat channel: A fragment-only editor resource forces
AgentHostSessionHandlerto rediscover the child inSessionState.chats, which races catalog hydration and renders "Cannot resolve chat". Encode the exactahp-chat://subagent/...channel in an internal query parameter, validate its chat id and owning backend session, and subscribe directly. -
Model subagents as chats, not sessions: A subagent spawned from a tool call belongs to the parent session as an additional chat with
origin.kind === "tool", hidden from the chat tab strip. Do not callrestoreSessionfor subagents; that creates_sessionStateswithout a matching_chatStatesentry, so later chat actions hit "Action for unknown chat". Add a chat on the parent session and dispatch the subagent turn to that chat URI. -
Keep case-sensitive ids out of URI authority: URI authorities are case-insensitive, so do not place tool call ids in the
ahp-chatauthority. Subagent chat URIs use a stablesubagentauthority and put the encoded tool call id in the path; usebuildSubagentChatUri(...)instead ofbuildChatUri(..., \subagent-${toolCallId}`)`. -
Selected custom agent must be in the SDK's
customAgents, not justpluginDirectories: The Copilot SDK validates the session-startagent:option (passed tocreateSession/resumeSession) against thecustomAgentslist by name only — it does NOT consultpluginDirectories.copilotSessionLauncher._buildSessionConfigdeliberately omits agents from file-dir plugins fromcustomAgents(relying on the SDK'spluginDirectoriesdiscovery to avoid duplicates), so selecting a plugin/extension-contributed agent (e.g. "Inbox") otherwise fails withCustom agent '<name>' not found. The fix (toSdkSessionCustomAgents) force-adds the resolved selected agent intocustomAgentswhile every other file-dir agent still loads viapluginDirectories. Note the agent picker offers VS Code chat modes fromIChatModeService, but onlyplugin/extensionstorage agents are synced to the host (SYNCABLE_STORAGE_SOURCES);user/localagents are never synced, so_resolveAgentNamereturnsundefinedfor them and noagent:is sent. -
Derive SDK custom-agent names exactly like
parseAgentFile:_resolveAgentNameresolves the selected agent through the plugin parser, which trims the frontmattername(getStringValue('name')?.trim() || nameFromFile). When building the SDKcustomAgentslist (toSdkCustomAgents), derive the name the same way (?.trim() || agent.name); reading the raw frontmatternamewithout trimming yields a config name that won't match the trimmedresolvedAgentName, so the SDK still rejects the session withCustom agent '<name>' not found. -
Peer chats have no server
summary, so dedup side-channel dispatch against the last value sent for that chat: equality guards before dispatchingSessionModelChanged/SessionAgentChangedcompare againstsummary.model/summary.agent, which only exist for the session's default chat. For peer chats, track the last-dispatched model/agent on theAgentHostChatSessioninstance (auto-cleaned on dispose) and diff against that — otherwise every peer-chat turn redundantly re-dispatches (and re-resolves the agent), and an intentional "clear selection" (undefined) can't be detected. -
Scrollable transcript surfaces must use workbench scrollbars: Don't make Agents/voice transcript regions scrollable with native
overflow-y: autoon the content node. Wrap transcript content inDomScrollableElement/list widgets so scrollbars match VS Code theming and remain usable in narrow auxiliary-window layouts. -
Background-sending a multi-chat composer must reset the composer before dispatching the send, not concurrently: in
NewChatInSessionWidget._send, creating the replacement untitled chat (openNewChatInSession({ forceNew: true })→provider.createNewChat) and the fire-and-forget backgroundsendRequestboth reach into shared chat-session state (acquireOrLoadSession/getOrCreateChatSession) for chats in the same group. Running them concurrently (send first, reset second) raced and left the sent chat stuck spinning with its message never dispatched, plus a second empty "New Chat" tab. Fullyawaitthe composer reset first, then fire the background send so it runs on its own. -
Chat tab order is the provider's stable creation order; don't reorder in the renderer: the agent host delivers
state.chatsin stable creation order (append on add, replace-in-place on update — seeagentHostStateManager/the session reducer), and a genuinely new chat is appended last. The renderer's rebuild autorun (chatCompositeBar.ts) must render that order as-is. Do not partition/move in-composerUntitledchats to the end: a draft is already last, and reordering by status makes a tab jump when a draft commits out of creation order (e.g. sending the 3rd of three drafts first moved it to the front). A chat'sUntitledpresentation (viaAdditionalChat._isNew, needed sosessionView.tsshows the composer) is independent of tab order and must not drive it. Also note_restorePeerChats(agentService.ts) must seed restored chats ingetChats()order, not inPromise.allresolution order, or the catalog scrambles on reload. -
A new chat must report
SessionStatus.Untitleduntil its first request is sent, regardless of how the provider creates it:sessionView.tsonly shows the new-chat composer (which owns the Alt+Enter background-send handler) whenactiveChat.status === Untitled. The agent host commits a new peer chat eagerly, so its host status isCompleted— surfacing the standard chat widget and breaking background send. Gate the chat's presented status on a provider-sideisNewflag (AdditionalChat.markNew/markSent, set increateNewChatand cleared insendRequest's committed-chat branch), not on the host-reported status. -
Service operations should return a result or throw, not
undefinedfor unsupported cases: capability-gated operations likeforkChatInSessionmust throw when the provider/session cannot perform them. Keep fallback decisions in the caller before invoking the service instead of encoding fallback as anundefinedservice result. -
A provisional session abandoned during commit detection must not be returned as successful: its status can remain
InProgressafter its lifecycle owner is disposed, so consumers waiting for a terminal status never settle. Clean up the provisional session and reject the send when commit detection times out or the connection is lost. -
Drop a fork when its turn point is unknown, don't forward it empty: in
AgentService.createChat/createSession, if the requested forkturnId/turnIndexresolves to no source turns, setfork: undefinedand fall through to a fresh create. Forwarding the fork with an empty turn slice makes the Copilot provider callsessions.forkwith notoEventId, inheriting the entire backend conversation while the new chat UI is seeded with zero turns — an inconsistent hidden-history chat. -
Side-chat context belongs to the provider, not AgentService message mutation:
AgentServicerecords and forwards the side-chat origin, but must not synthesize a first-turnChatattachment or strip provider-added context on restore. Each supporting provider establishes hidden backend context and removes inherited/provider-added history from the turns it returns. -
MessageAttachmentKind.Chatis generic and may reference unloaded chats: resolve chat attachments through a generic async path, enforce same-session ownership before hydration, and restore the referenced session/chat when it is absent from the state manager. Do not name this logic after side chats or assume/btwis its only producer. -
Agent capabilities are provider-specific: do not implement side chats for an agent merely because the protocol supports them. Advertise
multipleChats.sideChatand run shared side-chat tests only for providers with a complete provider-owned context/restore implementation. -
User-created side chats use the standard peer-chat tab model; only tool-origin subagents stay hidden by default: a
ChatOriginKind.SideChatchat is a normal user-facing peer chat, so it must flow throughvisibleChatTabs, the Conversations menu, pickers, and close/reopen like any other peer chat. Do not create a separate editor/detail surface for it; reserve the hidden/read-only default only for tool-origin subagents. -
/btwmust bypass queue/steer, may anchor toactiveTurn, and should activate the new peer chat through the normal sessions API: mark the silent slash commandexecuteDuringRequestso the chat widget invokes it independently, validate its anchor against completed turns or the current active turn, and after creating the side chat activate it viaISessionsService.openChat(...)before sending on that chat. Provider side-chat creation must lock on the new chat, not the source send key. Wrap the first provider prompt with a succinct instruction to prefer explanation over action and avoid work unless explicitly requested; include bounded user-visible active-turn markdown when native forks omit it, then strip the private wrapper from reconstructed visible history. Never inject reasoning or tool payloads. -
A responsive-layout autorun must re-baseline (not react) to controller-driven restores, holding the flag across the async reveal: the desktop [D7] responsive sidebar hides the sessions sidebar when small + editor + aux-bar are all open. Switching sessions restores layout via two async paths — the desktop aux-bar restore (
openView/openViewContainer) and the base controller's editor working-set apply (_applyWorkingSet, which reveals the editor part after anawaitand runs on aSequencermicrotask). Both reveal parts in a later autorun run, so an inline "same-run session changed" check only absorbs the synchronous transition and the async reveal still auto-hid the sidebar on navigation. Fix: a shared base-controller_withSessionLayoutRestore(work)epoch wraps both restore paths (the working-set wrap is the critical one for non-modal editors); the D7 autorun re-baselines_previousSpaceConstrainedwhile_isRestoringSessionLayoutis true. Also gate the constrained derivation on!multipleSessionsVisibleObsso the feature is disabled with multiple sessions visible. Never use asetTimeoutto bridge the async reveal — tie the flag to the actual promise. -
A promise-tied "epoch" helper must decrement synchronously for void/sync work, only deferring for real Promises:
_withSessionLayoutRestoreincrements a depth counter, runswork(), and decrements when done. If it always schedules the decrement on a microtask (Promise.resolve(result).finally(...)) — even whenwork()returnsundefined(the common no-op restore, e.g. a session with no workspace) — the depth stays elevated for the entire synchronous caller/test body, so_isRestoringSessionLayoutreadstrueforever and the consumer (D7) silently stops acting. Only defer the decrement whenwork()returns a thenable; for void/sync (or throwing) work, decrement in thefinally. -
A quick-chat's workspace-less kind is seeded at adapter construction and only ever promoted — every path that can carry
_metamust carry it:AgentHostSessionAdapterseeds its session-kind (QuickChatSessionKindvsWorkspaceSessionKind) fromreadSessionWorkspaceless(metadata._meta)in the constructor, and_promoteToQuickChatIfWorkspaceless(fromupdate()/setMeta()) later flips it to a quick chat the first time an authoritative_metasays workspace-less — never back, since an absent marker means "not included", not "cleared". So the_meta.workspacelesstag must ride on every metadata path:_refreshSessions()/listSessions, the live_handleSessionAdded(summary)notification, and both ends of the AHProot/listSessionsround-trip (protocolServerHandler.tsandremoteAgentHostProtocolClient.tsbuild their wire items field-by-field, andsatisfies SessionSummarydoes not catch a dropped optional field — this is exactly how the bug shipped twice). Dropping it makes a committed quick chat render under a section header labelled with its raw session UUID, leaking<userHome>/.copilot/chats/<id>as aworkspace(breaking the archive-on-delete fallback, list badges, changes/files) until a later_metaheals it._persistCachemust overlay the adapter's liveisQuickChatrather than the_metaByRawIdsnapshot, or the nextupdateAdaptersilently strips the marker from the startup cache. On the host,AgentService.listSessions()overlays_meta.workspacelessonto the provider listing from the persistedagentHost.workspacelesssession-database key (AH_META_WORKSPACELESS_DB_KEY) (the providers themselves,
This file is truncated. Read the full SKILL.md on GitHub.
Frequently asked questions about Sessions Management
Similar skills
Spring Boot Testing
Master testing techniques for Spring Boot 4 applications.
GitHub Issues
Manage GitHub issues efficiently with MCP tools.
Geofeed Tuner
Optimize your IP geolocation feeds in CSV format.
Batch Files
Master Windows batch scripting for automation and task management.
Adobe Illustrator Scripting
Automate your Illustrator workflows with ExtendScript.
Plugin Structure
Create and organize Claude Code plugins effectively.
