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
Problem — Research Environments are first-class entities (git repos with research-environment.toml, shared skills/insights/methods) but invisible in the sidebar unless a project happens to have an environment pill badge. There's no way to browse an environment's contents, discover which environments are active, or navigate to an environment from the sidebar. The concept deserves its own accordion section.
Approach — Add a "Research Environments" accordion section above "Research Projects" in the sidebar. Extend SidebarTreeService.getRoots() to collect environment roots from two sources: workspace folders with research-environment.toml (currently filtered out) and environments resolved from bound project declarations (auto-surfaced). Each environment is a full-citizen browsable file tree — same rendering, git status, and context menus as projects. A left accent border in the environment's 8-color palette links it visually to the matching pills on its bound projects. applyActiveProject() gains an environment cascade: when a session switch or composer project selection highlights a project, the bound environment also scrolls into view, expands, and highlights.
Approaches considered
Separate EnvironmentTreeService — a dedicated service for environment discovery and listing. Rejected: duplicates resolution logic, file-tree reading, and git status plumbing for no real separation-of-concerns benefit, since environments use the identical rendering as projects.
Webview-side grouping only — stop filtering environments from getRoots() and let the webview assemble the section. Rejected: the webview lacks filesystem access for resolving environments from project bindings (the 3-strategy resolver runs on the extension host).
Scope — in: new accordion section, environment root discovery, full file-tree rendering, active-environment highlighting cascade, context menus adapted by source, empty states for all sections, CONTEXT.md glossary entry · out: environment lifecycle/phase/status, virtual project children inside environments, global registry browsing, auto-adding environments to workspace, dismissing auto-surfaced environments
Assumptions — The TreeRoot type already supports projectType: "environment" in the bridge types (the webview's local redeclaration needs updating — see Notes). The 3-strategy environment resolver and the 8-color palette infrastructure ship with #880. The SidebarTreeService reads directories via vscode.workspace.fs.readDirectory with file URIs (not scoped to workspace folders), so auto-surfaced environments are browsable without being workspace members.
Acceptance Criteria
Section rendering
A "Research Environments" accordion section renders in the sidebar
The section appears above "Research Projects" in the default section order (["environments", "research", "dev", "fleet"])
The section is drag-reorderable like all other sections
For existing users with a persisted section order that includes "research" but not "environments", "environments" inserts before "research" (not appended to end)
Environment discovery
Workspace folders with research-environment.toml appear as roots in the environments section (no longer filtered out)
Environments resolved from open projects' [environment].slug bindings appear as roots in the environments section (auto-surfaced)
Environments are deduped by slug — each slug appears at most once
When the same environment is both a workspace folder and resolved from a binding, the workspace folder path takes precedence
Environment roots from workspace folders have source: "workspace"; roots from project bindings have source: "resolved"
boundProjectCount is the count of open research projects in the workspace bound to the environment's slug; it updates on each getRoots() call (e.g., when a project workspace folder is added or removed)
Root rendering
Each environment root displays its name from the TOML manifest
Each environment root displays a muted bound-project count after the name (e.g., "3 projects" / "1 project"), omitted when 0
Each environment root has a left accent border in its 8-color palette color (same palette as the existing pills)
No pill badge on the environment root itself
Expanding an environment root shows its directory tree — files, folders, git status coloring, identical to project roots
Git status colors propagate to files inside expanded environment roots (for workspace-folder environments via the existing watcher; for auto-surfaced environments on re-expand)
No virtual project children inside an expanded environment
TreeRoot data model
TreeRoot gains boundProjectCount?: number
TreeRoot gains source?: "workspace" | "resolved" indicating how the environment was discovered
Active environment highlighting
When a session switch highlights a project, the project's bound environment (if any) also scrolls into view, expands, and highlights with its palette-colored left border
When a composer project selection highlights a project, the same environment cascade fires
When a panel refocus re-emits the active project, the same environment cascade fires
All three applyActiveProject modes apply the environment cascade: "reset" highlights + expands + scrolls the environment (collapsing other environments); "expand" highlights + expands + scrolls; "none" highlights the environment border only (no expand, no scroll) — matching their respective project behavior
If the environments section is collapsed, it auto-expands when the cascade targets an environment within it
When the active project changes, the previous environment's highlight clears
If the active project has no bound environment, no environment is highlighted
Context menus
Environment roots with source: "workspace" show "Remove from Workspace" in the context menu
Environment roots with source: "resolved" show "Add to Workspace" instead
Both sources show: Reveal in Finder, Open in Terminal, Copy Path
Child entries (files/directories inside an expanded environment) have standard context menus identical to project children
Section header actions
"+" button on the section header triggers createNewEnvironment() (existing)
"Add existing" button (hover) opens a folder picker, validates research-environment.toml exists, and adds the folder to the workspace
Empty states (all sections)
The "Research Environments" section renders with "No environments yet" when no environments exist
The "Research Projects" section renders with "No projects yet" when no research projects are open (instead of disappearing)
The "Development Projects" section renders with "No dev projects open" when no dev projects are open (instead of disappearing)
"Fleet" section continues to render its existing placeholder
Empty sections still show their header with the "+" action button (where applicable)
Glossary
CONTEXT.md gains a "Research Environment" entry in the "Work organization" section
Testing Decisions
Extend the existing sidebar test suites:
test/sidebar_env_pill.test.ts — extend or add cases for environment root rendering (left border, project count, no pill)
test/sidebar_env_tree.test.ts — extend for environment section discovery and dedup
test/sidebar_view.test.ts — extend for section ordering, empty states, context menu adaptation
test/project/resolve_environment.test.ts — existing resolver tests remain; no new resolution logic
New: test/sidebar_active_env.test.ts — environment cascade in applyActiveProject across all three modes
Key Decisions
Discovery scope is workspace-relevant, not global. The environments section shows environments from workspace folders and project bindings only — not the full ~/.amico/environments.toml registry. The registry is a resolution fallback, not a browsing surface.
Auto-surfaced environments are full citizens. Environments resolved from project bindings are fully browsable (file tree, git status, context menus) despite not being workspace folders. The tree service reads directories via vscode.workspace.fs.readDirectory with file URIs, making this possible without workspace membership.
No auto-add to workspace. Auto-surfaced environments do not become workspace folders automatically. This avoids workspace clutter and reload prompts. Users can explicitly "Add to Workspace" from the context menu. Trade-off: no live file watcher on auto-surfaced environments (changes require collapse/re-expand to refresh).
No dismiss for auto-surfaced environments. The section reflects binding reality. If a project declares an environment, it appears. Removing it requires unbinding the project (modifying research-project.toml), which is an intentional decision.
Environment highlighting uses palette color, not yellow. The active project gets yellow (Harmoniqs brand). Its bound environment gets the environment's own palette color on the left border. Two visually distinct but linked highlights.
All sections render even when empty (behavioral inversion). The current renderRoots adds sections to available only when they have content, and the rendering loop guards on array length. This inverts that: all known section keys are always available, and the rendering loop unconditionally creates each section, inserting a placeholder when the root list is empty. Each section retains its header actions.
Data Contracts
TreeRoot additions:
boundProjectCount?: number // count of open research projects bound to this environment
source?: "workspace" | "resolved" // discovery source: workspace folder vs project binding
Default section order:
["environments", "research", "dev", "fleet"]
Section key:"environments" — used for expand/collapse state, drag ordering, and sectionExpanded persistence.
Constraints & Invariants
Environment roots are deduped by slug — one entry per slug regardless of how many projects bind to it or whether it's also a workspace folder
Workspace-folder path takes precedence over resolved path in dedup
When multiple workspace folders share the same environment slug, the first in workspace-folder order wins
The environment cascade in applyActiveProject() must not break existing project highlighting behavior
No environment-specific file watcher for auto-surfaced environments — the existing workspace watcher covers workspace-folder environments; auto-surfaced environments refresh on expand
Context menu "Add to Workspace" / "Remove from Workspace" is determined solely by source, never by heuristic
Section ordering migration is idempotent: if the saved order already contains "environments", no insertion is performed; otherwise "environments" inserts before "research"
Prior Art
SidebarTreeService (sidebar_tree_service.ts) — the tree scanning service this extends
sidebar_webview.tsrenderRoots() / applyActiveProject() — the rendering pipeline gaining the new section and highlight cascade
resolve_environment.ts — the 3-strategy resolver producing auto-surfaced environment data
Builds on #880 (Research Environments infrastructure)
Notes
The renderRootNode() function is extended with minimal additions for environment roots: a left accent border CSS class and the bound-project-count label. The function already handles the TreeRoot shape; environment-specific rendering is additive.
The webview's local TreeRoot interface (sidebar_webview.ts) redeclares the type without "environment" in the projectType union — this needs updating alongside the rendering loop.
The resolveSectionOrder() function needs an idempotent migration path for the new "environments" key — existing logic appends unknown keys, but we want "environments" before "research".
The bound-project-count label uses singular/plural: "1 project" vs "N projects".
The current renderSectionHeader creates exactly one action button (the "+" button). The "Add existing" hover button for the environments section requires either parameterizing renderSectionHeader to accept multiple action configurations or adding post-render wiring for the environments section specifically. The same pattern should be reusable for the Research Projects section header.
The webview's sectionExpanded initialization and saveSectionState are hardcoded to three keys (research, dev, fleet) — both need updating to include "environments".
Important
Problem — Research Environments are first-class entities (git repos with
research-environment.toml, shared skills/insights/methods) but invisible in the sidebar unless a project happens to have an environment pill badge. There's no way to browse an environment's contents, discover which environments are active, or navigate to an environment from the sidebar. The concept deserves its own accordion section.Approach — Add a "Research Environments" accordion section above "Research Projects" in the sidebar. Extend
SidebarTreeService.getRoots()to collect environment roots from two sources: workspace folders withresearch-environment.toml(currently filtered out) and environments resolved from bound project declarations (auto-surfaced). Each environment is a full-citizen browsable file tree — same rendering, git status, and context menus as projects. A left accent border in the environment's 8-color palette links it visually to the matching pills on its bound projects.applyActiveProject()gains an environment cascade: when a session switch or composer project selection highlights a project, the bound environment also scrolls into view, expands, and highlights.Approaches considered
getRoots()and let the webview assemble the section. Rejected: the webview lacks filesystem access for resolving environments from project bindings (the 3-strategy resolver runs on the extension host).Scope — in: new accordion section, environment root discovery, full file-tree rendering, active-environment highlighting cascade, context menus adapted by source, empty states for all sections, CONTEXT.md glossary entry · out: environment lifecycle/phase/status, virtual project children inside environments, global registry browsing, auto-adding environments to workspace, dismissing auto-surfaced environments
Assumptions — The
TreeRoottype already supportsprojectType: "environment"in the bridge types (the webview's local redeclaration needs updating — see Notes). The 3-strategy environment resolver and the 8-color palette infrastructure ship with #880. TheSidebarTreeServicereads directories viavscode.workspace.fs.readDirectorywith file URIs (not scoped to workspace folders), so auto-surfaced environments are browsable without being workspace members.Acceptance Criteria
Section rendering
["environments", "research", "dev", "fleet"])"research"but not"environments","environments"inserts before"research"(not appended to end)Environment discovery
research-environment.tomlappear as roots in the environments section (no longer filtered out)[environment].slugbindings appear as roots in the environments section (auto-surfaced)source: "workspace"; roots from project bindings havesource: "resolved"boundProjectCountis the count of open research projects in the workspace bound to the environment's slug; it updates on eachgetRoots()call (e.g., when a project workspace folder is added or removed)Root rendering
TreeRoot data model
TreeRootgainsboundProjectCount?: numberTreeRootgainssource?: "workspace" | "resolved"indicating how the environment was discoveredActive environment highlighting
applyActiveProjectmodes apply the environment cascade:"reset"highlights + expands + scrolls the environment (collapsing other environments);"expand"highlights + expands + scrolls;"none"highlights the environment border only (no expand, no scroll) — matching their respective project behaviorContext menus
source: "workspace"show "Remove from Workspace" in the context menusource: "resolved"show "Add to Workspace" insteadSection header actions
createNewEnvironment()(existing)research-environment.tomlexists, and adds the folder to the workspaceEmpty states (all sections)
Glossary
Testing Decisions
Extend the existing sidebar test suites:
test/sidebar_env_pill.test.ts— extend or add cases for environment root rendering (left border, project count, no pill)test/sidebar_env_tree.test.ts— extend for environment section discovery and deduptest/sidebar_view.test.ts— extend for section ordering, empty states, context menu adaptationtest/project/resolve_environment.test.ts— existing resolver tests remain; no new resolution logictest/sidebar_active_env.test.ts— environment cascade inapplyActiveProjectacross all three modesKey Decisions
Discovery scope is workspace-relevant, not global. The environments section shows environments from workspace folders and project bindings only — not the full
~/.amico/environments.tomlregistry. The registry is a resolution fallback, not a browsing surface.Auto-surfaced environments are full citizens. Environments resolved from project bindings are fully browsable (file tree, git status, context menus) despite not being workspace folders. The tree service reads directories via
vscode.workspace.fs.readDirectorywith file URIs, making this possible without workspace membership.No auto-add to workspace. Auto-surfaced environments do not become workspace folders automatically. This avoids workspace clutter and reload prompts. Users can explicitly "Add to Workspace" from the context menu. Trade-off: no live file watcher on auto-surfaced environments (changes require collapse/re-expand to refresh).
No dismiss for auto-surfaced environments. The section reflects binding reality. If a project declares an environment, it appears. Removing it requires unbinding the project (modifying
research-project.toml), which is an intentional decision.Environment highlighting uses palette color, not yellow. The active project gets yellow (Harmoniqs brand). Its bound environment gets the environment's own palette color on the left border. Two visually distinct but linked highlights.
All sections render even when empty (behavioral inversion). The current
renderRootsadds sections toavailableonly when they have content, and the rendering loop guards on array length. This inverts that: all known section keys are always available, and the rendering loop unconditionally creates each section, inserting a placeholder when the root list is empty. Each section retains its header actions.Data Contracts
TreeRootadditions:Default section order:
Section key:
"environments"— used for expand/collapse state, drag ordering, andsectionExpandedpersistence.Constraints & Invariants
applyActiveProject()must not break existing project highlighting behaviorsource, never by heuristic"environments", no insertion is performed; otherwise"environments"inserts before"research"Prior Art
SidebarTreeService(sidebar_tree_service.ts) — the tree scanning service this extendssidebar_webview.tsrenderRoots()/applyActiveProject()— the rendering pipeline gaining the new section and highlight cascaderesolve_environment.ts— the 3-strategy resolver producing auto-surfaced environment dataSource
Builds on #880 (Research Environments infrastructure)
Notes
renderRootNode()function is extended with minimal additions for environment roots: a left accent border CSS class and the bound-project-count label. The function already handles theTreeRootshape; environment-specific rendering is additive.TreeRootinterface (sidebar_webview.ts) redeclares the type without"environment"in theprojectTypeunion — this needs updating alongside the rendering loop.resolveSectionOrder()function needs an idempotent migration path for the new"environments"key — existing logic appends unknown keys, but we want"environments"before"research".renderSectionHeadercreates exactly one action button (the "+" button). The "Add existing" hover button for the environments section requires either parameterizingrenderSectionHeaderto accept multiple action configurations or adding post-render wiring for the environments section specifically. The same pattern should be reusable for the Research Projects section header.sectionExpandedinitialization andsaveSectionStateare hardcoded to three keys (research,dev,fleet) — both need updating to include"environments".