Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Python Environment Tools (PET) - AI Coding Agent Instructions

## Project Overview

This is a high-performance Rust-based tool for discovering Python environments and virtual environments. It operates as a JSONRPC server consumed by the VS Code Python extension to avoid spawning Python processes repeatedly.

## Architecture

### Core Concepts

- **Locators**: Modular environment discovery components implementing the `Locator` trait (`crates/pet-core/src/lib.rs`)
- **JSONRPC Server**: Main communication interface (`crates/pet/src/jsonrpc.rs`) with stdio/stdout protocol
- **Environment Types**: 15+ supported Python installations (Conda, Poetry, PyEnv, Homebrew, Windows Store, etc.)
- **Reporter Pattern**: Asynchronous environment discovery reporting via the `Reporter` trait

### Key Architecture Files

- `crates/pet/src/locators.rs` - Ordered locator creation and fallback identification logic
- `crates/pet/src/find.rs` - Multi-threaded environment discovery coordination
- `crates/pet-core/src/lib.rs` - Core traits and configuration structures
- `docs/JSONRPC.md` - Complete API specification with TypeScript interfaces

## Development Workflow

### Building & Testing

```bash
# Standard build
cargo build

# Release build (optimized for performance)
cargo build --release

# Run tests with specific CI features
cargo test --features ci
cargo test --features ci-poetry-global

# Run JSONRPC server
./target/debug/pet server
```

### Feature-Gated Testing

Tests use feature flags for different environments:

- `ci` - General CI environment tests
- `ci-jupyter-container` - Jupyter container-specific tests
- `ci-homebrew-container` - Homebrew container tests
- `ci-poetry-*` - Poetry-specific test variants

### Locator Development Pattern

When adding new environment types:

1. **Create new crate**: `crates/pet-{name}/`
2. **Implement Locator trait**: Key methods are `try_from()` (identification) and `find()` (discovery)
3. **Add to locator chain**: Update `create_locators()` in `crates/pet/src/locators.rs` - ORDER MATTERS
4. **Platform-specific**: Use `#[cfg(windows)]`, `#[cfg(unix)]`, `#[cfg(target_os = "macos")]`

Example structure:

```rust
impl Locator for MyLocator {
fn get_kind(&self) -> LocatorKind { LocatorKind::MyType }
fn supported_categories(&self) -> Vec<PythonEnvironmentKind> { vec![PythonEnvironmentKind::MyType] }
fn try_from(&self, env: &PythonEnv) -> Option<PythonEnvironment> { /* identification logic */ }
fn find(&self, reporter: &dyn Reporter) { /* discovery logic */ }
}
```

## Critical Patterns

### Performance Principles (from `crates/pet/README.md`)

1. **Avoid spawning processes** - Extract info from files/filesystem when possible
2. **Report immediately** - Use Reporter pattern for async discovery
3. **Complete information** - Gather all environment details in one pass, not incrementally

### JSONRPC Communication Flow

1. Client sends `configure` request (must be first)
2. Client sends `refresh` request to discover environments
3. Server sends `environment` notifications as discoveries happen
4. Optional: `resolve` request for individual Python executables

### Testing Verification Pattern

Tests validate discovered environments using 4 verification methods:

1. Spawn Python to verify `sys.prefix` and `sys.version`
2. Use `try_from()` with executable to get same info
3. Test symlink identification
4. Use `resolve` method for consistency

## Environment-Specific Notes

### Conda Environments

- Supports detection from history files and conda-meta directories
- Manager detection via spawning conda executable in background threads
- Complex prefix/name relationships for base vs named environments

### Poetry Environments

- Hash-based environment naming: `{project-name}-{hash}-py`
- Project-specific virtual environments in configured cache directories
- Configuration hierarchy: local poetry.toml → global config

### Platform Differences

- **Windows**: Registry + Windows Store detection, different path separators
- **macOS**: Xcode Command Line Tools, python.org, Homebrew paths
- **Linux**: Global system paths (`/usr/bin`, `/usr/local/bin`)

## Common Gotchas

- **Locator order matters** in `create_locators()` - more specific before generic
- **Thread safety** - Heavy use of Arc/Mutex for concurrent discovery
- **Feature flags** - Many tests only run with specific CI features enabled
- **Path canonicalization** - Symlink resolution varies by platform
- **Caching** - Optional cache directory for expensive operations (conda spawning)

## Files to Read First

1. `docs/JSONRPC.md` - Understanding the external API
2. `crates/pet/src/locators.rs` - Core architecture patterns
3. `crates/pet-core/src/lib.rs` - Essential traits and types
4. `crates/pet/tests/ci_test.rs` - Comprehensive testing patterns


## Scripts
- Use `cargo fetch` to download all dependencies
- Use `rustup component add clippy` to install Clippy linter
- Use `cargo fmt --all` to format code in all packages
- Use `cargo clippy --all-features -- -Dwarnings` to check for linter issues
- Use `cargo clippy --all-features --fix --allow-dirty -- -Dwarnings` to automatically fix linter issues
- Use `cargo build` to build the project
- Use `cargo test --all` to test all packages (this can take a few seconds)
- Use `cargo test [TESTNAME]` to test a specific test
- Use `cargo test -p [SPEC]` to test a specific package
- Use `cargo test --all` to test all packages
38 changes: 38 additions & 0 deletions .github/prompts/analyze.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
mode: agent
description: Root cause analysis for a bug in the codebase.
tools: ['codebase', 'editFiles', 'fetch', 'findTestFiles', 'githubRepo', 'search', 'searchResults', 'usages', 'vscodeAPI', 'github', 'get_file_contents', 'get_issue', 'get_issue_comments', 'list_issues', 'list_pull_requests', 'search_code', 'search_issues', 'memory', 'sequentialthinking', 'activePullRequest', 'websearch']
---
You are an expert in this codebase.

Your goal is to analyze a bug or add the new feature, for this you first need to:
* Understand the context of the bug or feature by reading the issue description and comments.
* Ask for clarification from user only if the issue description is not clear.
* Understand the codebase by reading the relevant instruction files and code.
* If its a bug, then identify the root cause of the bug, and explain this to the user.
* If just a number is provided by the user, assume it is an issue number and fetch the issue details.

Based on your above understanding generate a summary of your analysis.
Ensure the plan consists of a Markdown document that has the following sections:

* Overview: A brief description of the bug/feature. If its a bug, then is this bydesign or a bug?
* Root Cause: A detailed explanation of the root cause of the bug, including any relevant code snippets or references to the codebase. (only if it's a bug)
* Requirements: A list of requirements to resolve the bug or add the new feature.
* Additional Considerations: Mention any potential challenges or risks associated with the implementation.
* Proposal: Can and should a solution be implemented? Is it a bug, or is this by design? What are the risks or challenges associated with a solution if it is a feature?

Do not make any code edits, just generate a plan. Use thinking and reasoning skills to outline the steps needed to achieve the desired outcome.

<reminder>
MUST:
- Read instruction file(s) before analyzing code
- Understand codebase, issue and architecture thoroughly
- Perform root cause analysis only if the issue is a bug
- Never make any assumptions, always strive to be thorough and accurate
- Avoid unnecessary repetition and verbosity
- Be concise, but thorough.

MUST NOT:
- Make code changes
- Mention all new or updated lines of code
</reminder>
40 changes: 40 additions & 0 deletions .github/prompts/explain.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
mode: agent
description: Analyze the codebase and explain a feature/component in detail.
tools: ['codebase', 'editFiles', 'fetch', 'findTestFiles', 'githubRepo', 'search', 'searchResults', 'usages', 'vscodeAPI', 'search_code', 'memory', 'sequentialthinking', 'websearch']
---
# Code Explanation Guide
You are an expert in this codebase.
Your task is to analyze the user requests and explain the feature/component in detail. Where possible use diagrams to depict the architecture and or flow.

Start by first:
* Understand what needs explaining.
- Read instruction files for the relevant area
- Examine code with appropriate tools
- Understand the codebase by reading the relevant instruction files and code.
- Identify design patterns and architectural decisions
- Use available tools to gather information
- Be thorough before presenting any explanation

Based on your above understanding generate a markdown document that explains the feature/component in detail.
Use thinking and reasoning skills when generating the explanation & ensure the document has the following sections:

* Overview: Brief summary of the feature/component and its purpose.
* Architecture: High-level architecture diagram (if applicable).
* Key Components: List and describe key components involved.
* Data Flow: Explain how data moves through the system.
* Control Flow: Describe the control flow and how components interact.
* Integration Points: Explain how this feature/component integrates with others.
* Additional Considerations: Mention any potential challenges or risks associated with understanding or modifying this feature/component.
Mention any other relevant information that would help in understanding the feature/component.


<reminder>
MUST:
- Do not make any other code edits.
- Read instruction file(s) before analyzing code
- Understand codebase, issue and architecture thoroughly
- Never make any assumptions, always strive to be thorough and accurate
- Avoid unnecessary repetition and verbosity
- Be concise, but thorough.
</reminder>
13 changes: 13 additions & 0 deletions .github/prompts/implement.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
mode: agent
description: Executed after a plan has been created to implement a bug fix or feature request.
tools: ['codebase', 'editFiles', 'fetch', 'findTestFiles', 'githubRepo', 'problems', 'runTasks', 'runTests', 'search', 'searchResults', 'terminalLastCommand', 'terminalSelection', 'testFailure', 'usages', 'vscodeAPI', 'github', 'get_file_contents', 'get_issue', 'get_issue_comments', 'list_issues', 'list_pull_requests', 'search_code', 'search_issues', 'memory', 'sequentialthinking', 'activePullRequest', 'copilotCodingAgent', 'websearch']
---
You are an expert in this codebase.
Your task is to now implement the solution.

<reminder>
MUST:
- Adhere to patterns and best practices of the project
- Add required tests to ensure the fix works
</reminder>
40 changes: 40 additions & 0 deletions .github/prompts/plan.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
mode: agent
description: Analyze a bug/issue in the codebase and report findings without making code changes.
tools: ['codebase', 'editFiles', 'fetch', 'findTestFiles', 'githubRepo', 'search', 'searchResults', 'usages', 'vscodeAPI', 'github', 'get_file_contents', 'get_issue', 'get_issue_comments', 'list_issues', 'list_pull_requests', 'search_code', 'search_issues', 'memory', 'sequentialthinking', 'activePullRequest', 'websearch']
---
You are an expert in this codebase.

Your goal is to prepare a detailed plan to fix the bug or add the new feature, for this you first need to:
* Understand the context of the bug or feature by reading the issue description and comments.
* Ask for clarification from user only if the issue description is not clear.
* Understand the codebase by reading the relevant instruction files and code.
* If its a bug, then identify the root cause of the bug, and explain this to the user.
* If just a number is provided by the user, assume it is an issue number and fetch the issue details.

Based on your above understanding generate a plan to fix the bug or add the new feature.
Ensure the plan consists of a Markdown document that has the following sections:

* Overview: A brief description of the bug/feature.
* Problem: A detailed explanation of the root cause of the bug, including any relevant code snippets or references to the codebase. (only if it's a bug)
* Solution: A brief summary of the solution including a list of requirements to resolve the bug or add the new feature.
* Additional Considerations: Mention any potential challenges or risks associated with the implementation.
* Implementation Steps: A detailed list of steps to implement the bug fix or new feature.
Note: Limit information to what is necessary for developers and AI assistants to understand the implementation steps.
Note: Adhere to architecture, development and testing patterns in instruction files

Do not make any code edits, just generate a plan. Use thinking and reasoning skills to outline the steps needed to achieve the desired outcome.

<reminder>
MUST:
- Understand codebase, issue and architecture thoroughly
- Adhere to patterns and best practices of the project
- Perform root cause analysis only if the issue is a bug
- Never make any assumptions, always strive to be thorough and accurate
- Avoid unnecessary repetition and verbosity
- Be concise, but thorough.

MUST NOT:
- Make code changes
- Mention all new or updated lines of code
</reminder>
13 changes: 12 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions crates/pet-conda/src/conda_rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ envs_path:
"#;

assert_eq!(
parse_conda_rc_contents(&cfg).unwrap().env_dirs,
parse_conda_rc_contents(cfg).unwrap().env_dirs,
[
PathBuf::from("/Users/username/dev/envs"),
PathBuf::from("/opt/conda/envs"),
Expand All @@ -373,7 +373,7 @@ envs_dirs:
"#;

assert_eq!(
parse_conda_rc_contents(&cfg).unwrap().env_dirs,
parse_conda_rc_contents(cfg).unwrap().env_dirs,
["/Users/username/dev/envs", "/opt/conda/envs",].map(PathBuf::from)
);

Expand All @@ -388,7 +388,7 @@ envs_path:
"#;

assert_eq!(
parse_conda_rc_contents(&cfg).unwrap().env_dirs,
parse_conda_rc_contents(cfg).unwrap().env_dirs,
[
PathBuf::from("/opt/somep lace/envs"),
expand_path(PathBuf::from("~/dev/envs2"))
Expand All @@ -402,7 +402,7 @@ channels:
channel_priority: strict
"#;

assert!(parse_conda_rc_contents(&cfg).unwrap().env_dirs.is_empty(),);
assert!(parse_conda_rc_contents(&cfg).unwrap().files.is_empty(),);
assert!(parse_conda_rc_contents(cfg).unwrap().env_dirs.is_empty(),);
assert!(parse_conda_rc_contents(cfg).unwrap().files.is_empty(),);
}
}
6 changes: 3 additions & 3 deletions crates/pet-conda/src/environments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ fn is_conda_env_name_in_cmd(cmd_line: String, name: &str) -> bool {
// # cmd: /Users/donjayamanne/miniconda3/bin/conda create -n conda1
// # cmd_line: "# cmd: /usr/bin/conda create -p ./prefix-envs/.conda1 python=3.12 -y"
// Look for "-n <name>" in the command line
cmd_line.contains(format!("-n {}", name).as_str())
|| cmd_line.contains(format!("--name {}", name).as_str())
cmd_line.contains(format!("-n {name}").as_str())
|| cmd_line.contains(format!("--name {name}").as_str())
}

pub fn get_activation_command(
Expand Down Expand Up @@ -364,7 +364,7 @@ mod tests {
#[test]
#[cfg(unix)]
fn verify_conda_env_name() {
let mut line = "# cmd: /Users/donjayamanne/.pyenv/versions/mambaforge-22.11.1-3/lib/python3.10/site-packages/conda/__main__.py create --yes --name .conda python=3.12";
let line = "# cmd: /Users/donjayamanne/.pyenv/versions/mambaforge-22.11.1-3/lib/python3.10/site-packages/conda/__main__.py create --yes --name .conda python=3.12";
assert!(is_conda_env_name_in_cmd(line.to_string(), ".conda"));

let mut line = "# cmd: /Users/donjayamanne/.pyenv/versions/mambaforge-22.11.1-3/lib/python3.10/site-packages/conda/__main__.py create --yes -n .conda python=3.12";
Expand Down
Loading
Loading