# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview **WoodShop** - Voice-driven conversational 3D woodworking & furniture modeler. Speak (or type) commands like *"place a 6 foot 2x4, sand it, attach a 2 foot 2x4 at 90 degrees 10 inches from the end"* and watch the model build in a live 3D viewport — Holodeck-style. ## Architecture **Design principle:** reuse existing CmdForge tools for everything that isn't woodshop-specific; don't reinvent voice/AI plumbing. ``` woodshop-talk (driver.py) ── the conversational loop │ dictate ............... speech→text (CmdForge tool, reused) │ pa-load-tools ......... wood-* → Claude schemas (reused) │ claude -p ............. interpret utterance → JSON tool calls (reused provider) │ pa-execute-tool ....... dispatch each wood-* tool (reused) │ read-aloud ........... speak confirmation (reused) ▼ scene.json ← single source of truth (parts, joints, selection, undo stack) ▲ │ writes │ reads/mutates ▼ wood-* CmdForge tools woodshop-view (viewer.py) (place/join/sand/delete/undo) watches scene.json → live pyvista 3D thin wrappers over `woodshop` CLI ``` Only woodshop-specific code lives in this repo: the scene model (`scene.py`), nominal→actual lumber table (`lumber.py`), length parsing (`units.py`), the `woodshop` CLI (`cli.py`), build123d geometry + STL/STEP export (`geometry.py`), the pyvista viewport (`viewer.py`), and the driver (`driver.py`). The driver uses Claude (not `pa-tool-loop`, which hard-wires a small local model) for reliable structured tool-calling. ### Entry points | Command | Purpose | |---------|---------| | `woodshop` (no args) / `woodshop-gui` | **The unified desktop studio** (viewport + parts panel + command bar) | | `woodshop ` | CLI ops: place, join, stand, lay, rotate, move, trim, copy, rename, sand, delete, select, undo, redo, clear, status, cutlist, export, render, save, open, projects | | `woodshop-view` | Standalone live 3D viewport (watches `scene.json`; labels, grid, isometric) | | `woodshop-talk` | Standalone conversational driver (`--voice` for mic, `--once "..."` for one command) | The studio (`src/woodshop/gui/`) is a thin PySide6 shell over the same Scene + operations + interpreter: - `controller.py` — one in-memory `Scene`; buttons/menus call typed methods, voice/typed commands go through `driver.interpret` and are applied via `execute_call`, which **reuses the CLI command functions** (no behavioral drift). Every mutation saves to disk and emits `changed`. - `viewport.py` — embedded `pyvistaqt.QtInteractor`; click a board to select. - `panels.py` — parts list (ExtendedSelection: Ctrl/Shift multi-select) + selected-part inspector (editable length/yaw/tilt) + quick-action buttons. `command_bar.py` — text + push-to-talk + transcript, with slow work (LLM/dictate/TTS) on a `QThreadPool` (`workers.py`). - `numpad.py` — a numberpad control panel (2/4/6/8 move, 1/3/7/9 rotate, +/− raise/lower, 0/. front/iso, 5 fit) that also responds to the **physical numpad keys** (MainWindow.keyPressEvent forwards them when not typing). - **Multi-selection**: `controller.selected` is a list driven by 3D Ctrl+click (`viewport.picked` carries an additive flag) and list multi-select. Group ops (`move_selected`/`rotate_selected`/stand/lay/sand/delete) apply to all selected in one undo step via `scene.batch()`. Voice "move these" works because the selected ids are fed into the interpreter prompt. Scene file location: `$WOODSHOP_SCENE` or `~/.local/share/woodshop/scene.json`. Named projects: `~/.local/share/woodshop/projects/.json`. Parts have full 3D orientation (`yaw_deg`/`tilt_deg`/`roll_deg`) so legs and uprights stand vertically. Parts can be referred to by id (`p1`) or by a name set with `rename`. The cut list (`cutlist.py`) reports board-feet and an 8'-stick shopping estimate. ### CmdForge tools (the documented command vocabulary) `wood-place`, `wood-join`, `wood-sand`, `wood-delete`, `wood-undo` live in `~/.cmdforge//` and wrap the `woodshop` CLI. Regenerate them with `/tmp/gen_wood_tools.py` (kept in the repo plan) if their schemas change. The arg descriptions ARE the LLM's documentation, so keep them clear. ### Setup ```bash python3 -m venv .venv && source .venv/bin/activate pip install -e ".[viewer,dev]" # viewer extra pulls build123d + pyvista pytest # 25 tests ``` ### Known limitations / next steps 1. **Joins are flush butt joints**: B's end sits flush against A's surface, and B is aligned to A's reference corner (top faces level + one side flush) rather than centered. The flush corner is fixed (A's +width/+thick side; no per-join choice of which corner / centered). 2. **Joinery features** (`Feature` on each `Part`) are parametric ops applied in `geometry.part_solid`: `tenon` fuses a protruding tongue; `mortise`/`hole`/ `slot`/`dado`/`rabbet` cut a box/cylinder into a face; `chamfer` bevels the edges around a face via build123d `chamfer()` (handled specially — `_apply_chamfer`, with a try/except fallback for over-sized bevels). The viewport tessellates featured boards (plain boards stay fast pyvista boxes). Edit paths: CLI `feature/feature-edit/feature-delete/features`; voice `wood-feature`/`wood-feature-delete`; **GUI Joinery tab** (`feature_panel.py`) — add-with-default then edit fields; `controller.active_feature` is the one being edited. Not yet: countersinks, and click-a-face-to-place in the GUI. 2. **Latency** ~7–13s per utterance (one `claude -p` call). 3. Voice path (`--voice`) reuses `dictate`; the driver loop is hardened against failures but the mic path isn't exercised in the unit tests. 4. Auto-placement of parts in a multi-step "build a table" request depends on the LLM choosing good offsets; geometry is correct but corners may need nudging. ## ⚠️ CRITICAL: Updating Todos, Milestones, and Goals **DO NOT edit `todos.md`, `milestones.md`, or `goals.md` files directly.** These files are managed by Development Hub which has file watchers and sync logic. Direct edits will be overwritten or cause conflicts. **Use the `devhub-tasks` CLI instead:** ```bash # Status overview devhub-tasks status woodshop # Add todos devhub-tasks todo add woodshop "Task description" --priority high --milestone M1 # Complete todos (by text match or ID number) devhub-tasks todo complete woodshop "Task description" devhub-tasks todo complete woodshop 3 # List todos devhub-tasks todo list woodshop # Add milestones devhub-tasks milestone add woodshop M2 --name "Milestone Name" --target "March 2026" # Complete milestones (also completes linked todos) devhub-tasks milestone complete woodshop M1 # Goals devhub-tasks goal add woodshop "Goal description" --priority high devhub-tasks goal complete woodshop "Goal description" ``` Use `--json` flag for machine-readable output. Run `devhub-tasks --help` for full documentation. **Files you CAN edit directly:** `overview.md`, `architecture.md`, `README.md`, and any other docs. ## Development Commands ```bash # Install for development pip install -e ".[dev]" # Run tests pytest # Run a single test pytest tests/test_file.py::test_name ``` ## Architecture *TODO: Describe the project architecture* ### Key Modules *TODO: List key modules and their purposes* ### Key Paths - **Source code**: `src/woodshop/` - **Tests**: `tests/` - **Documentation**: `docs/` (symlink to project-docs) ## Documentation Documentation lives in `docs/` (symlink to centralized docs system). **Before updating docs, read `docs/updating-documentation.md`** for full details on visibility rules and procedures. Quick reference: - Edit files in `docs/` folder - Use `public: true` frontmatter for public-facing docs - Use `` / `` to hide sections - Deploy: `~/PycharmProjects/project-docs/scripts/build-public-docs.sh woodshop --deploy` Do NOT create documentation files directly in this repository.