From 1e5c207821c42904f1ccb10f0bed4b895411188d Mon Sep 17 00:00:00 2001 From: Miguel Angel Ajo Pelayo Date: Wed, 17 Sep 2025 08:38:37 +0000 Subject: [PATCH] Add some cursor rules to help us better us AI assistants --- .cursor/rules/creating-new-drivers.mdc | 108 +++++++++++++++++ .cursor/rules/project-structure.mdc | 162 +++++++++++++++++++++++++ __templates__/create_driver.sh | 11 +- docs/source/contributing.md | 16 +++ 4 files changed, 293 insertions(+), 4 deletions(-) create mode 100644 .cursor/rules/creating-new-drivers.mdc create mode 100644 .cursor/rules/project-structure.mdc diff --git a/.cursor/rules/creating-new-drivers.mdc b/.cursor/rules/creating-new-drivers.mdc new file mode 100644 index 000000000..cdfc94787 --- /dev/null +++ b/.cursor/rules/creating-new-drivers.mdc @@ -0,0 +1,108 @@ +--- +description: when the user is requesting to create, improve or document a new driver +alwaysApply: false +--- +# Creating New Drivers + +When asked to create a new driver, follow these steps: + +## 1. Use the Driver Creation Script +Always use the provided script: `./__templates__/create_driver.sh` + +## 2. Required Information +Before creating a driver, ask the user for: +- **Driver Package Name**: The package name (e.g., `mydriver`, `custom-power`, `device-controller`) + - Should be lowercase with hyphens for multi-word names + - Examples from existing drivers: `network`, `iscsi`, `ridesx`, `opendal`, `shell`, `gpiod`, `http-power`, `tasmota`, `tftp`, `uboot`, `snmp`, `sdwire`, `probe-rs`, `can`, `composite`, `corellium`, `dutlink`, `energenie`, `flashers`, `http`, `power`, `pyserial`, `qemu`, `ustreamer`, `yepkit` +- **Driver Class Name**: The main driver class in CamelCase (e.g., `MyDriver`, `CustomPower`, `DeviceController`) + - Should be descriptive and end with appropriate suffix based on functionality + - Examples: `TcpNetwork`, `ISCSI`, `RideSXDriver`, `Opendal`, `Shell`, `HttpPower`, `TasmotaPower`, `Tftp`, `UbootConsole`, `SNMPServer`, `SDWire`, `ProbeRs`, `Can`, `Composite`, `Corellium`, `Dutlink`, `EnerGenie`, `QemuFlasher`, `UStreamer`, `Ykush` +- **Author Name**: Full name of the author +- **Author Email**: Email address of the author + +## 3. Command Format +```bash +./__templates__/create_driver.sh "" "" +``` +Always try to obtain the Author Name and Email from git, by checking the git configuration. +## 4. Examples +```bash +# Network driver +./__templates__/create_driver.sh network TcpNetwork "John Doe" "john@example.com" + +# Power management driver +./__templates__/create_driver.sh custom-power CustomPowerDriver "Jane Smith" "jane@example.com" + +# Device control driver +./__templates__/create_driver.sh device-controller DeviceController "Bob Wilson" "bob@example.com" +``` + +## 5. After Creation +Once the driver is created: +1. Navigate to the new driver directory: `packages/jumpstarter-driver-/` +2. Review the generated files and customize as needed +3. Implement the driver logic in `driver.py` +4. Add tests in `driver_test.py` +5. Update the README.md with specific documentation +6. Test the driver: `make pkg-test-` + +## 6. Driver Naming Conventions +- **Package names**: lowercase with hyphens (e.g., `my-driver`) +- **Class names**: CamelCase with descriptive suffixes: + - Power drivers: `*Power` (e.g., `TasmotaPower`, `HttpPower`) + - Network drivers: `*Network` (e.g., `TcpNetwork`, `UdpNetwork`) + - Flasher drivers: `*Flasher` (e.g., `QemuFlasher`) + - Console drivers: `*Console` (e.g., `UbootConsole`) + - Server drivers: `*Server` (e.g., `HttpServer`, `SNMPServer`) + - Generic drivers: descriptive name (e.g., `ISCSI`, `Shell`, `Tftp`) + +## 7. Directory Structure +The script creates: +``` +packages/jumpstarter-driver-/ +├── jumpstarter_driver_/ +│ ├── __init__.py +│ ├── client.py +│ ├── driver.py +│ └── driver_test.py +├── examples/ +│ └── exporter.yaml +├── .gitignore +├── pyproject.toml +└── README.md +``` + +## 8. Documentation +The script automatically creates: +- A README.md with basic documentation +- A symlink in `docs/source/reference/package-apis/drivers/` pointing to the README +- Template files for all necessary components +- A good example of documentation is in `docs/source/reference/package-apis/drivers/gpiod.md` and also `docs/source/reference/package-apis/drivers/pyserial.md` + +## Code Style and Testing + +- Follow existing code style (validate with `make lint`, fix with `make lint-fix`) +- Perform static type checking with `make ty-pkg-${package_name}` +- Add comprehensive tests and update documentation +- Verify all tests pass (`make test-pkg-${package_name}` or `make test`) + +## Contributing Guidelines + +- Focus on a single issue per driver +- Use clear, descriptive commit messages +- Reference issue numbers when applicable +- Follow conventional commit format when possible +- Ensure all tests pass before submitting PRs + +# Driver client CLIs + +Some drivers implement known classes that provide a CLI interface for the driver, but other +clients implement their own CLI interface that will appear in the `j` command inside a `jmp shell`. + +Good examples can be found in `packages/jumpstarter-driver-shell/jumpstarter_driver_shell/client.py`, `packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/client.py` or `packages/jumpstarter-driver-probe-rs/jumpstarter_driver_probe_rs/client.py`. + +# Composite drivers + +Drives which have children drivers should be composite drivers, and the client interface should +inherit from `CompositeClient` in jumpstarter_driver_composite.client, also the pyproject.toml should +have a dependency on `jumpstarter-driver-composite`. \ No newline at end of file diff --git a/.cursor/rules/project-structure.mdc b/.cursor/rules/project-structure.mdc new file mode 100644 index 000000000..6807f3b98 --- /dev/null +++ b/.cursor/rules/project-structure.mdc @@ -0,0 +1,162 @@ +--- +alwaysApply: true +--- + +# Project Structure + +This project follows a monorepo structure with a top-level `pyproject.toml` that manages all packages using UV workspace. + +## Top-Level Structure + +``` +jumpstarter/ +├── pyproject.toml # Main workspace configuration +├── packages/ # All Python packages +├── examples/ # Example applications +├── docs/ # Documentation +├── __templates__/ # Templates for creating new drivers +└── .cursor/ # Cursor AI rules +``` + +## Workspace Configuration + +The project uses **UV workspace** for dependency management: + +- **Top-level `pyproject.toml`**: Defines the workspace and includes all packages +- **Workspace members**: All packages in `packages/*` and `examples/*` are included +- **Dependency groups**: Shared development dependencies (docs, dev) +- **Tool configuration**: Ruff, typos, coverage, pytest settings + +## Package Structure + +### Core Packages + +- **`jumpstarter/`**: Main library with client, config, and common functionality +- **`jumpstarter-protocol/`**: gRPC protocol definitions (excluded from linting) +- **`jumpstarter-kubernetes/`**: Kubernetes integration +- **`jumpstarter-testing/`**: Testing utilities +- **`jumpstarter-imagehash/`**: Image hashing utilities + +### CLI Packages + +- **`jumpstarter-cli/`**: Main CLI application +- **`jumpstarter-cli-admin/`**: Administrative CLI commands +- **`jumpstarter-cli-common/`**: Shared CLI utilities +- **`jumpstarter-cli-driver/`**: Driver-specific CLI commands + +### Driver Packages + +All driver packages follow the pattern `jumpstarter-driver-/`: + +- **`jumpstarter-driver-network/`**: Network interface drivers (TCP, UDP, Unix, etc.) +- **`jumpstarter-driver-power/`**: Power management drivers +- **`jumpstarter-driver-*`**: Various hardware-specific drivers + +### Utility Packages + +- **`jumpstarter-all/`**: Meta-package that includes all components +- **`hatch-pin-jumpstarter/`**: Custom Hatch build hook + +## Package Structure + +Each package follows this structure: + +``` +packages/jumpstarter-driver-/ +├── jumpstarter_driver_/ # Main Python package +│ ├── __init__.py +│ ├── driver.py # Driver implementation +│ ├── client.py # Client implementation +│ └── driver_test.py # Tests +├── examples/ # Example configurations +│ └── exporter.yaml +├── pyproject.toml # Package configuration +├── README.md # Package documentation +└── .gitignore +``` + +## Package Configuration + +Each package's `pyproject.toml` includes: + +- **Project metadata**: Name, description, authors, license, please note that this repo only accepts Apache-2.0 license. +- **Dependencies**: Runtime and development dependencies +- **Entry points**: Driver and adapter registrations +- **Build system**: Hatch with custom hooks +- **Version management**: VCS-based versioning from root + +## Examples Structure + +``` +examples/ +├── automotive/ # Automotive testing example +│ ├── jumpstarter_example_automotive/ +│ ├── pyproject.toml +│ └── README.md +└── soc-pytest/ # SoC testing example + ├── jumpstarter_example_soc_pytest/ + ├── pyproject.toml + └── README.md +``` + +## Development Workflow + +### Creating New Packages + +1. **Drivers**: Use `./__templates__/create_driver.sh` (see creating-new-drivers.mdc) +2. **Other packages**: Create manually following existing patterns + +### Package Dependencies + +- **Core packages**: Depend on `jumpstarter-protocol` +- **Driver packages**: Depend on `jumpstarter` and specific hardware libraries +- **CLI packages**: Depend on `jumpstarter` and `jumpstarter-cli-common` +- **Examples**: Depend on relevant driver packages + +### Testing + +- **Package tests**: `make test-pkg-` +- **All tests**: `make test` +- **Coverage**: Configured per package with HTML and XML reports + +### Linting and Formatting + +- **Ruff**: Code formatting and linting (excludes `jumpstarter-protocol`), `make lint` and `make lint-fix` are available. +- **Typos**: Spell checking +- **Pre-commit**: Automated checks + +## Key Conventions + +1. **Naming**: Package names use hyphens, module names use underscores +2. **Entry points**: Drivers register via `jumpstarter.drivers` entry point +3. **Versioning**: All packages share the same version from VCS +4. **Documentation**: Each package has its own README.md, and when it's a driver we make a symlink in `docs/source/reference/package-apis/drivers/` pointing to the README.md for the driver. +5. **Testing**: Comprehensive test coverage required, but always try to focus on starting a server and client to test it e2e. Mock sometimes when there is too much dependency on system tools/services/compatibility issues between MacOs/Linux. +6. **Dependencies**: Minimal, focused dependencies per package + +## Build and Distribution + +- **Build system**: Hatch with custom `hatch-pin-jumpstarter` hook +- **Version source**: VCS (Git) with root-level version management +- **Distribution**: Individual packages published separately +- **Workspace**: UV manages dependencies across all packages + +## Running tests + +When running tests you should use the `make pkg-test-` command. + +## Running type checking + +When running type checking you should use the `make pkg-ty-` command, +never invoke pytest manually. Use this because it will be more reliable and +install the right dependencies. + +## Running linting + +When running linting you should use the `make lint-fix`command. + +## Running python manually + +If you need to run python code manually to check if it works, you should use `uv run python3` +to make sure you get the venv from uv, you may need to run `make sync` first to get all +the dependencies in place. \ No newline at end of file diff --git a/__templates__/create_driver.sh b/__templates__/create_driver.sh index c43d266eb..c5ca89752 100755 --- a/__templates__/create_driver.sh +++ b/__templates__/create_driver.sh @@ -11,7 +11,7 @@ set -euxv if [ "$#" -ne 4 ]; then echo "Illegal number of parameters" echo "Usage: create_driver.sh " - echo "Example: create_driver.sh mydriver MyDriver \"John Something\" john@somewhere.com" + echo "Example: create_driver.sh my-driver MyDriver \"John Something\" john@somewhere.com" exit 1 fi @@ -20,6 +20,9 @@ export DRIVER_CLASS=$2 export AUTHOR_NAME=$3 export AUTHOR_EMAIL=$4 +# Convert hyphens to underscores for Python module name +export DRIVER_MODULE_NAME=$(echo "${DRIVER_NAME}" | sed 's/-/_/g') + # MacOS has a different syntax for sed -i, we either use gsed (GNU sed) or apply the right -i syntax if command -v gsed &> /dev/null; then sed_cmd="gsed" @@ -31,7 +34,7 @@ fi # create the driver directory DRIVER_DIRECTORY=packages/jumpstarter-driver-${DRIVER_NAME} -MODULE_DIRECTORY=${DRIVER_DIRECTORY}/jumpstarter_driver_${DRIVER_NAME} +MODULE_DIRECTORY=${DRIVER_DIRECTORY}/jumpstarter_driver_${DRIVER_MODULE_NAME} # create the module directories mkdir -p ${MODULE_DIRECTORY} mkdir -p ${DRIVER_DIRECTORY}/examples @@ -61,7 +64,7 @@ Example configuration: ```yaml export: ${DRIVER_NAME}: - type: jumpstarter_driver_${DRIVER_NAME}.driver.${DRIVER_CLASS} + type: jumpstarter_driver_${DRIVER_MODULE_NAME}.driver.${DRIVER_CLASS} config: # Add required config parameters here ``` @@ -71,7 +74,7 @@ export: Add API documentation here. EOF # Need to expand variables after EOF to prevent early expansion -$sed_cmd "s/\${DRIVER_CLASS}/${DRIVER_CLASS}/g; s/\${DRIVER_NAME}/${DRIVER_NAME}/g" "${README_FILE}" +$sed_cmd "s/\${DRIVER_CLASS}/${DRIVER_CLASS}/g; s/\${DRIVER_NAME}/${DRIVER_NAME}/g; s/\${DRIVER_MODULE_NAME}/${DRIVER_MODULE_NAME}/g" "${README_FILE}" echo "README.md file content:" cat "${README_FILE}" diff --git a/docs/source/contributing.md b/docs/source/contributing.md index e2db79b50..1af84f788 100644 --- a/docs/source/contributing.md +++ b/docs/source/contributing.md @@ -49,6 +49,22 @@ If you have questions, reach out in our Matrix chat or open an issue on GitHub. We welcome bug fixes, features, and improvements to the core codebase. + +## AI Assistants + +This project accepts contributions from AI assistants, although you should be careful when creating code from AI assistants, +and figure out if the code you are submitting could infringe any licensing, for example, reusing code from other incompatible +GPL licenses, you should do your due diligence. + +This project includes cursor rules to help Cursor AI understand our codebase and development patterns. When working with Cursor AI: + +- **Driver Creation**: If asked to create a new driver, Cursor will guide you through the process using our `create_driver.sh` script +- **Code Style**: Cursor will follow our established patterns and conventions +- **Testing**: Cursor will remind you to add tests and run our test suite + +The cursor rules are located in `.cursor/rules/` directory, with specific guidance for driver creation in `.cursor/rules/creating-new-drivers.mdc`. + + ### Contributing Drivers To create a new driver scaffold: