Imported from spkane/freecad-macro-cut-for-magnets (
AGENTS.md). Install upstream withnpx skills add spkane/freecad-macro-cut-for-magnets. Copyright stays with the author.
AGENTS.md - AI Assistant Guidelines for This Project
Project Overview
This is a FreeCAD macro that cuts a 3D object along a plane and adds aligned magnet holes to both pieces. It's designed for creating parts that snap together with magnets - perfect for 3D printing large objects that exceed printer bed size.
Key Features
- Cut objects along XY, XZ, YZ planes or custom datum planes
- Automatically adds aligned magnet holes to both pieces
- Smart hole placement with configurable clearance
- Surface penetration detection to avoid holes breaking through outer surfaces
Critical: Python Version Must Match FreeCAD
CRITICAL: This project MUST use the same Python version that the current stable FreeCAD release bundles internally. FreeCAD embeds a specific Python version (e.g., libpython3.11.dylib), and using a different Python version causes fatal crashes due to ABI incompatibility.
Before changing the Python version in .mise.toml or pyproject.toml:
- Check which Python version FreeCAD bundles:
- macOS:
ls /Applications/FreeCAD.app/Contents/Resources/lib/libpython* - Linux:
ls /usr/lib/freecad/lib/libpython*or check FreeCAD's Python console
- macOS:
- The Python minor version (e.g., 3.11) must match exactly
- Using Python 3.12+ with FreeCAD that bundles Python 3.11 will crash
Current requirement: Python 3.11. FreeCAD 1.0.x is CI-verified; FreeCAD 1.1.x, including 1.1.3, is the current stable target and must pass the integration gate before being advertised as fully supported. Always confirm the installed FreeCAD bundle's Python minor version before changing this requirement.
Project Structure
freecad-macro-cut-for-magnets/
├── .github/workflows/ # CI/CD workflows
├── docs/ # MkDocs documentation
├── just/ # Just module files
├── macro/Cut_Object_for_Magnets/ # Main macro source
│ ├── __init__.py # Package init (required for imports)
│ ├── CutObjectForMagnets.FCMacro # Main macro file (GUI + entry point)
│ ├── cut_magnets_core.py # Pure Python logic (no FreeCAD imports)
│ ├── cut_magnets_fc.py # FreeCAD-dependent logic
│ ├── CutObjectForMagnets.svg # Icon
│ └── README-CutObjectForMagnets.md
├── tests/
│ ├── unit/ # pytest unit tests (no FreeCAD required)
│ ├── freecad/ # FreeCAD integration tests
│ └── just_commands/ # Just command tests
├── scripts/ # Utility scripts
├── .pre-commit-config.yaml # Pre-commit hooks
├── justfile # Task runner
├── mkdocs.yaml # Documentation config
└── pyproject.toml # Project configuration
Macro Module Layout
Why This Structure?
The macro is split into three layers to enable automated testing:
-
cut_magnets_core.py - Pure Python logic (vector math, parameter validation, clearance calculations). Testable with standard pytest - no FreeCAD installation required.
-
cut_magnets_fc.py - FreeCAD-dependent logic (cutting operations, boolean ops, shape handling). Testable inside FreeCAD using its test framework.
-
CutObjectForMagnets.FCMacro - GUI dialog and entry point. Imports from modules when available, falls back to embedded definitions for standalone use.
Why __init__.py is Required
The __init__.py file makes the macro directory a proper Python package. This is required for:
- Import resolution: Allows
from cut_magnets_core import ...to work - Package metadata: Defines
__version__,__author__, etc. - Test discovery: pytest can properly discover and import modules
- Consistency: Both macro repos use the same structure
Standalone Macro Support
When users install just the .FCMacro file (without the module files), the macro still works because:
# In CutObjectForMagnets.FCMacro
_USE_MODULES = False
try:
from cut_magnets_core import HolePlacementError
_USE_MODULES = True
except ImportError:
pass
if not _USE_MODULES:
# Fallback: embedded definitions
class HolePlacementError(Exception):
pass
This fallback pattern ensures the macro works in both scenarios:
- Development/Full install: Uses modular code (testable)
- Standalone install: Uses embedded definitions (works without modules)
Development Environment Setup
Required Tools (managed via mise)
This project uses mise for local development tool management. All tool versions are pinned in .mise.toml.
# Install mise through a package manager (if not already installed)
# macOS:
brew install mise
# Linux/other platforms: use the package-manager or version-pinned install
# documented by mise, and verify checksums/signatures for direct downloads.
# Install all project tools
mise install
# Activate mise in your shell (add to .bashrc/.zshrc)
eval "$(mise activate bash)" # or zsh/fish
Package Management
This project supports both pip and uv for Python dependencies. CI uses uv for documentation builds, while local pure-Python development can use either path. Keep the dependency extras equivalent.
# Preferred, matches docs CI semantics
uv sync --extra dev --extra test --extra docs
# pip fallback for local development
pip install -e ".[dev,test,docs]"
Workflow Commands (via just)
This project uses just as a command runner.
# List all commands and modules
just
just list-all
# List commands in specific modules
just list-dev # Development utilities
just list-documentation # Documentation commands
just list-install # Installation commands
just list-quality # Code quality commands
just list-release # Release commands
just list-testing # Test commands
# Common workflows
just setup # Full dev setup (install pre-commit hooks)
just all # Run all quality checks
# Quality commands
just quality::check # Run all pre-commit checks
just quality::format # Format code with ruff
just quality::lint # Run linting
# Documentation commands
just documentation::build # Build documentation
just documentation::serve # Serve locally at http://localhost:8000
Code Quality Standards
Pre-commit Hooks
CRITICAL: This project uses pre-commit for all code quality checks. Before finishing ANY code changes:
- Run
just quality::checkorpre-commit run --all-files - Fix ALL issues reported
- Re-run until all checks pass
Pre-commit runs these checks:
Python Quality:
- Ruff: Linting and import sorting
- Ruff Format: Code formatting
- Bandit: Security vulnerability scanning
Secrets Detection:
- Gitleaks: Fast regex-based secrets scanning
- detect-secrets: Baseline tracking for known/approved secrets
Documentation & Config:
- Markdownlint: Markdown linting with auto-fix
- Codespell: Spell checking in code and docs
- YAML/JSON validation: Config file validation
Infrastructure:
- Actionlint: GitHub Actions workflow linting
- check-github-workflows: GitHub workflow schema validation
Linting Rules
- Follow PEP 8 style guidelines
- Use type hints for function signatures
- Maximum line length: 120 characters
- Use modern Python syntax (3.11+ features)
Running Pre-commit on Specific Files
IMPORTANT: After editing any files, always run pre-commit hooks:
# Run pre-commit on specific files
pre-commit run --files path/to/file1.py path/to/file2.py
# Or run on all files
pre-commit run --all-files
Testing
The macro has a hybrid testing approach with unit tests (pytest) and FreeCAD integration tests.
Project Structure for Testing
freecad-macro-cut-for-magnets/
├── macro/Cut_Object_for_Magnets/
│ ├── CutObjectForMagnets.FCMacro # Main macro
│ ├── cut_magnets_core.py # Pure Python logic (testable)
│ └── cut_magnets_fc.py # FreeCAD-dependent operations
└── tests/
├── unit/ # pytest tests for core logic
│ └── test_core.py
├── freecad/ # FreeCAD integration tests
│ └── test_cut_magnets.py
└── just_commands/ # Just command tests
├── conftest.py # Shared fixtures
└── test_*.py # Tests for each just module
Running Tests
# Run unit tests (no FreeCAD required)
just testing::unit
# Run unit tests with coverage
just testing::cov
# Run FreeCAD integration tests (requires FreeCAD)
just testing::freecad
# Run all tests
just testing::all
# Install test dependencies
just testing::install
# Run just command syntax tests (fast)
just testing::just-syntax
# Run just command runtime tests
just testing::just-runtime
# Run all just command tests
just testing::just-all
# Run full release test suite
just testing::release-test
Writing Tests
- Unit tests: Add to
tests/unit/test_core.pyfor pure Python logic - FreeCAD tests: Add to
tests/freecad/test_cut_magnets.pyfor FreeCAD operations - Just command tests: Add to
tests/just_commands/test_<module>.pyfor just commands
Just Command Tests
The tests/just_commands/ directory contains tests that verify all just commands work correctly:
- Syntax tests (
just_syntaxmarker): Validate commands parse correctly using--dry-run - Runtime tests (
just_runtimemarker): Actually execute commands and verify behavior
This ensures changes to the justfile or just modules don't break existing commands.
Documentation
Building Documentation
just documentation::build # Build documentation
just documentation::serve # Serve locally at http://localhost:8000
Documentation is built with MkDocs and deployed to GitHub Pages.
GitHub Pages Deployment
This repo uses artifact-based deployment (actions/deploy-pages@v4), which does not require a gh-pages branch.
Initial Setup (one-time):
- Go to repo Settings → Pages
- Under Build and deployment → Source, select "GitHub Actions"
- Save
Deployment triggers:
- Push to
mainbranch (if docs paths changed) - Manual trigger via Actions → Documentation → Run workflow
The workflow builds MkDocs and deploys directly via GitHub's artifact system. No branch management required.
File Extension Conventions
Use full file extensions, not DOS-style shortened versions:
| Correct Extension | Incorrect (DOS-style) |
|---|---|
.yaml |
.yml |
.jpeg |
.jpg |
.html |
.htm |
Macro Parameters Reference
Plane Settings
| Parameter | Values | Description |
|---|---|---|
| Plane Type | Preset/Model | Choose between preset or model plane |
| Preset Plane | XY, XZ, YZ | Axis-aligned cut planes |
| Offset | mm | Distance from origin for preset plane |
Hole Parameters
| Parameter | Default | Description |
|---|---|---|
| Diameter | 6.2mm | Hole diameter (add clearance for magnet) |
| Depth | 3.0mm | How deep holes go into each piece |
| Number of Holes | 6 | Total holes (evenly distributed) |
| Edge Clearance (Pref) | 2.0mm | Ideal distance from hole to outer edge |
| Edge Clearance (Min) | 0.5mm | Absolute minimum clearance |
Macro Installation
Quick Install (via just commands)
The easiest way to install the addon locally:
just install::addon # Install addon to FreeCAD Mod directory
just install::status # Check installation status
just install::uninstall # Remove addon from FreeCAD
just install::cleanup # Alias for uninstall
The install commands automatically detect FreeCAD's location based on your OS:
- macOS:
~/Library/Application Support/FreeCAD/Mod/ - Linux:
~/.local/share/FreeCAD/Mod/ - Windows:
%APPDATA%/FreeCAD/Mod/
For FreeCAD 1.x+, the commands also detect versioned directories (e.g., v1-1, v1-2).
Other Installation Methods
- Addon Manager: Search for "Cut Object for Magnets" in FreeCAD's Addon Manager
- Manual: Copy
CutObjectForMagnets.FCMacroto FreeCAD's Macro folder
Release Process
Releases follow a two-step process: bump, then tag.
Step 1: Bump Version
# Update version in all source files
just release::bump 1.0.0
# Review changes
git diff
# Commit
git add -A && git commit -m "chore: bump to 1.0.0"
The bump command updates:
macro/Cut_Object_for_Magnets/CutObjectForMagnets.FCMacro(__Version__and__Date__)package.xml(<version>and<date>)macro/Cut_Object_for_Magnets/wiki-source.txt(|Version=and|Date=)
Step 2: Create Release Tag
# Create and push the tag (triggers GitHub workflow)
just release::tag 1.0.0
The tag command:
- Verifies version in source files matches the tag
- Creates annotated git tag
- Pushes tag to origin
- Triggers GitHub Actions release workflow
Release Commands
just release::bump 1.0.0 # Update version in source files
just release::tag 1.0.0 # Create and push release tag
just release::version # Show current version
just release::list-tags # List all release tags
just release::latest-tag # Show latest release tag
Update FreeCAD Wiki (After Release)
just release::wiki-diff # Check differences from live wiki
just release::wiki-show # View wiki source content
just release::wiki-update # Copy to clipboard & open wiki edit page
Summary Checklist
When working on this project, ALWAYS:
- Use
misefor tool management - Use
justcommands for workflows - Write docstrings for all functions
- Run
just allbefore finishing - everything must pass - Run
just testing::unitto verify unit tests pass - Test manually in FreeCAD for UI changes
- Update RELEASE_NOTES.md before releases