Voice-driven conversational 3D woodworking & furniture modeler
Go to file
rob 970b88bc7b Portability + consistency polish (Codex review)
Housekeeping over features, per Codex: consistency and portability now matter
more than another feature.

- driver.scene_summary no longer hardcodes ~/PycharmProjects/.venv/bin/woodshop;
  new driver.woodshop_cmd() resolves the CLI portably (PATH, else `python -m
  woodshop`). Used by the voice/GUI status path.
- scripts/gen_wood_tools.py: CMDFORGE_PY overridable via env; generated tool
  bodies resolve `woodshop` at RUNTIME (shutil.which → python -m woodshop), no
  baked-in local path; file-writing moved under main()/__main__ (was running at
  import); PyYAML declared under dev deps.
- cutlist.py: drop the misleading "+10% waste" label — shopping already uses the
  kerf-aware CutPlan nesting.
- Docs refreshed (README + CLAUDE): real test count, parametric joinery is
  modeled, new cutplan/prices/estimate/inventory/colors modules + GUI windows,
  portable tool regeneration.
- tests: driver path discovery (PATH + module fallback), generated tool bodies
  compile and contain no hardcoded paths. 207 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 21:56:28 -03:00
scripts Portability + consistency polish (Codex review) 2026-05-30 21:56:28 -03:00
src/woodshop Portability + consistency polish (Codex review) 2026-05-30 21:56:28 -03:00
tests Portability + consistency polish (Codex review) 2026-05-30 21:56:28 -03:00
.gitignore Initial project setup 2026-05-29 00:59:35 -03:00
CLAUDE.md Portability + consistency polish (Codex review) 2026-05-30 21:56:28 -03:00
MATERIALS_INVENTORY_PLAN.md Material-aware pricing: oak ≠ pine 2026-05-30 19:48:26 -03:00
README.md Portability + consistency polish (Codex review) 2026-05-30 21:56:28 -03:00
SHOP_PACKET_PLAN.md Phase 1: bounded-exact lumber, guillotine plywood, Best-of-N 2026-05-30 15:37:11 -03:00
pyproject.toml Portability + consistency polish (Codex review) 2026-05-30 21:56:28 -03:00

README.md

WoodShop

Voice-driven conversational 3D woodworking & furniture modeler.

Talk to it like the Star Trek holodeck and watch furniture build itself:

"Place a 6 foot 2x4, sand it, then attach a 2 foot 2x4 at 90 degrees, 10 inches from the end."

"Build a coffee table: a four foot by two foot frame from 2x4s, with four legs 18 inches tall standing at the corners."

Each board is real dimensional lumber (a 2x4 is modeled at its true 1.5″ × 3.5″), so the result is buildable — export to STEP (CAD/CNC) or STL (3D print), and get a cut list with board-feet and a shopping estimate.

How it works

WoodShop reuses the existing CmdForge tool ecosystem for everything that isn't woodworking-specific, so no wheels are reinvented:

woodshop-talk ── the conversational loop
   │  dictate ............. speech → text          (CmdForge tool)
   │  pa-load-tools ....... wood-* → Claude schemas (CmdForge tool)
   │  claude -p ........... interpret → tool calls  (provider)
   │  pa-execute-tool ..... dispatch each wood-*     (CmdForge tool)
   │  read-aloud .......... speak confirmation       (CmdForge tool)
   ▼
scene.json  ← single source of truth (parts, joints, selection, undo)
   ▲                                   │ writes
   │ reads/mutates                     ▼
wood-* CmdForge tools          woodshop-view
(place/join/stand/move/...)    live pyvista 3D, watches scene.json

The wood-* tools are thin wrappers over the woodshop CLI, so the modeling logic lives in one place and the tools double as the LLM's documented command vocabulary.

Installation

python -m venv .venv && source .venv/bin/activate
pip install -e ".[gui,dev]"        # 'gui' pulls build123d + pyvista + PySide6 + pyvistaqt
python scripts/gen_wood_tools.py   # register the wood-* CmdForge tools

Usage

woodshop            # launches the unified desktop app

One window with the 3D viewport (click a board to select it; Ctrl+click to select several), a parts panel (list + selected-part inspector + quick-action buttons), a numberpad control panel (move/rotate the selection by clicking or with your keyboard's numpad — 2/4/6/8 move, 1/3/7/9 rotate, +/ raise/lower, 0/. front/iso, 5 fit), and a command bar where you type or push-to-talk (🎤). Mouse, keyboard, and voice all drive the same scene and the same visible selection — so "move these 4 inches", the numpad 8 key, and the move button are interchangeable, and act on every selected board at once (one undo). Menus cover New/Open/Save projects, Export STL/STEP, Save Image, Undo/Redo, camera views, and Build templates.

Standalone tools (headless / scripting)

woodshop-view &                    # just the live 3D window (watches the scene)
woodshop-talk                      # just the voice/text loop; --voice to speak
woodshop-talk --once "build a workbench top from five 2x6 boards 6 feet long"

Or drive it directly from the CLI:

woodshop place 2x4 "6 ft"          # place a board
woodshop stand                     # stand it up (a leg)
woodshop join p2 --to p1 --angle 90 --offset "10 in"
woodshop rename "front-left leg"
woodshop cutlist                   # bill of materials
woodshop export table.step         # STEP / STL export
woodshop save "coffee table"       # named projects
woodshop open "coffee table"

Run woodshop --help for the full command list (place, join, stand, lay, rotate, move, trim, copy, rename, sand, delete, undo, clear, status, cutlist, export, save, open, projects).

The active scene lives at $WOODSHOP_SCENE or ~/.local/share/woodshop/scene.json; named projects in ~/.local/share/woodshop/projects/.

Development

pytest                              # 200+ tests

Key modules:

Module Role
scene.py Part/Joint/Connection/Feature/Scene model, ops, undo, persistence
lumber.py nominal → actual dimensions, material colors/defaults
colors.py color name → hex + lightness blends for the viewer
units.py parse "6 ft" / "3 ft 6 in" / "-2 ft" → inches
cli.py the woodshop command
geometry.py build123d solids (incl. joinery booleans) + STL/STEP export
cutlist.py quick cut list / board-feet / shopping summary
cutplan.py the deterministic keystone: kerf-aware nesting, rough/final, batch, offcut reuse
prices.py editable price book (Kent NB) + material-aware cost estimate
estimate.py project quote: consumables + labor + suggested selling price
inventory.py shop-wide event-sourced stock / offcut / build ledger
instructions.py / jigs.py deterministic build steps & jig suggestions
viewer.py live pyvista 3D viewport (woodshop-view)
driver.py conversational loop (woodshop-talk)
gui/ the unified PySide6 studio (woodshop-gui), incl. the Cut List & BOM window
scripts/gen_wood_tools.py (re)generate the wood-* CmdForge tools

Known limitations

  • Joinery is parametric (tenon/mortise/dado/rabbet/hole/slot/chamfer as build123d boolean ops, with connections/assemblies); what's not modeled is joinery-fit compensation for material lost to sanding, and lap/pocket-hole presets. Boards still attach as flush butt joints unless you add features.
  • Render is flat colors per material/finish — no image textures (wood grain) yet.
  • Command interpretation latency is ~713s per utterance (one claude -p call).

License

MIT