Skip to content

Sidebar: Research Environments accordion section #895

Description

@jeonghun-jj-lee

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 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

  1. 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.

  2. 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.

  3. 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).

  4. 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.

  5. 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.

  6. 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

  1. 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
  2. Workspace-folder path takes precedence over resolved path in dedup
  3. When multiple workspace folders share the same environment slug, the first in workspace-folder order wins
  4. The environment cascade in applyActiveProject() must not break existing project highlighting behavior
  5. No environment-specific file watcher for auto-surfaced environments — the existing workspace watcher covers workspace-folder environments; auto-surfaced environments refresh on expand
  6. Context menu "Add to Workspace" / "Remove from Workspace" is determined solely by source, never by heuristic
  7. Section ordering migration is idempotent: if the saved order already contains "environments", no insertion is performed; otherwise "environments" inserts before "research"

Prior Art

Source

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".

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions