Skip to content

Implement project discovery from ~/.claude.json and filesystem scanning #98

@doomspork

Description

@doomspork

Context

Discovers projects from two sources: (1) the projects map in ~/.claude.json, and (2) optional filesystem scanning of common directories for .claude/ folders.

Ported from: Fig/Sources/Services/ProjectDiscoveryService.swift

What to implement

File path

  • fig-core/src/services/project_discovery_service.rs

Implementation

use std::path::{Path, PathBuf};
use crate::models::discovered_project::DiscoveredProject;
use crate::services::config_file_manager::ConfigFileManager;
use crate::error::FigResult;
use walkdir::WalkDir;

pub struct ProjectDiscoveryService {
    config_manager: ConfigFileManager,
}

const DEFAULT_SCAN_DIRS: &[&str] = &[
    "", "code", "Code", "projects", "Projects", "Developer",
    "dev", "src", "repos", "github", "workspace",
];

const SKIP_DIRS: &[&str] = &[
    "node_modules", ".git", ".svn", ".hg", "vendor", "Pods",
    ".build", "build", "dist", "target", "__pycache__",
    ".venv", "venv", ".cache", "Library", "Applications",
];

const MAX_SCAN_DEPTH: usize = 3;

impl ProjectDiscoveryService {
    pub fn new(config_manager: ConfigFileManager) -> Self { ... }

    /// Discovers all projects from legacy config + optional filesystem scan.
    pub fn discover_projects(&self, scan_filesystem: bool) -> FigResult<Vec<DiscoveredProject>> { ... }

    /// Discovers projects only from ~/.claude.json.
    pub fn discover_from_config(&self) -> FigResult<Vec<DiscoveredProject>> { ... }

    /// Scans filesystem for projects with .claude/ directories.
    pub fn scan_for_projects(&self) -> FigResult<Vec<DiscoveredProject>> { ... }

    /// Builds a DiscoveredProject from a directory path.
    fn build_discovered_project(&self, path: &Path) -> DiscoveredProject { ... }

    /// Returns scan directories relative to home.
    fn scan_directories(&self) -> Vec<PathBuf> { ... }
}

Sort results by last_modified (most recent first), then by display_name alphabetically.

Acceptance criteria

  • Discovers projects from legacy config
  • Optionally scans filesystem for .claude/ directories
  • Skips directories in SKIP_DIRS list
  • Respects MAX_SCAN_DEPTH of 3
  • Deduplicates projects found from both sources
  • Sorts by last modified (most recent first)
  • Populates has_settings, has_local_settings, has_mcp_config flags

Test requirements

  • test_discover_from_config — with temp dir + fixture config
  • test_skip_directories_respected
  • test_max_depth_respected
  • test_deduplication
  • test_sort_by_last_modified
  • test_build_discovered_project_flags

Dependencies

Requires: #93, #96

Blocks

#99, #123

Metadata

Metadata

Assignees

No one assigned

    Labels

    epic:project-explorerSidebar, project list, navigationepic:rust-migrationRust + Iced migration infrastructurephase:2Phase 2 — Editingpriority:highMust-have for MVPtype:migrationDirect port of existing Swift functionality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions