Repository navigation
Add benchup, a CLI and MCP server for editing .bup projects - #41
Merged
Merged
Conversation
Built on benchup-tools: list tools and schemas, read the scene, run any tool or an all-or-nothing batch as one undo step, undo/redo, and serve the same tools over MCP on stdio (protocol code from BenchUp3D#3). Saves are atomic and refuse to overwrite a file changed on disk. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- benchup open hands a .bup to the installed desktop app (bundle id on macOS, file association elsewhere), or to --app / BENCHUP_APP. - erase removes the joints of the boards it deletes (the core keeps them, BenchUp3D#36), refuses joint ids with a pointer to the new remove_joint tool, and the scene flags joints whose board is gone. - Scope errors name every object to open, from the outside in; the help, MCP instructions and enter_object say how long a group stays open. - find_objects: query is optional and its description matches what it does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From 12 scenarios run by agents with only the CLI help to go on: - Joints: add_joint picks the woodworking orientation (depth is where a goes into b; tongues and tenons across a's thickness, dovetails and laps across its broad side), validates ranges as the core does, refuses joints that cannot be cut, and get_object shows roles, settings, supported orientations and status. - Faces: outward normals use a ray-parity test instead of "away from the part's centre", which flipped faces of concave parts and made push_pull go the wrong way. Concave faces get a center too. - New tools: create_stock_material, move_to, check_model (unjoined overlaps, uncuttable or orphaned joints, open solids, loose geometry), get_cut_list and get_guide. resize_board takes an anchor. - push_pull and draw_polyline return what they create (face_id), group brings a face's edges along, and the scene lists axes (front is -y), loose geometry ids, dimensions, texts and component definitions. - CLI: "$N.field" references between batch calls, --dry-run, --brief, the project name in scene, benchup guide, and a Claude Code skill. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The app saves projects as a PNG preview with the document in a private buPd chunk, but benchup-tools only read gzip and plain JSON, so the CLI could not open files saved by the desktop app. The format now lives in benchup_tools::files and project_files.rs delegates to it. The CLI keeps a file's container when it saves: a PNG keeps its (now stale) preview with the document chunk replaced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/agent-guide.md is compiled into the tools (benchup guide, get_guide), so the guide in the binary always matches it, and maintainers review it with the other docs. docs/cli.md is the user documentation for the CLI; the crate README points to both. The guide now reflects the second round of agent tests: joints on one board must keep 1 to 2 mm apart (backs in a groove when shelves are housed, drawer bottoms in the sides only, tenon depth below P - s - t), components cannot be joined to outside boards, dry runs ending with check_model, result fields and nested references, leaning pieces built upright and rotated by -θ, and recipes for cut lists and dimensions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- add_joint names the joints already on the boards when a new one cannot be cut, refuses boards at different group levels and assemblies with a clear reason, and returns a and b. - check_model confirms box overlaps with the real solids (no alarm for a notched board around a post), warns when a joint's roles look reversed, follows materials set on parent groups, and reports the size of the boards rather than of the annotations around them. - get_cut_list explains how to get minimum_stock_pieces; joint kinds use add_joint's names; push_pull also returns face_id; group explains a group of loose geometry; --brief keeps a scene's objects; descriptions say what tools return and what happens to joints. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the third round of agent tests: - Editing tools open the group around their targets for the call when all ids share one, as push_pull already did; enter_object is only needed to create parts inside a group. - flip_joint swaps a joint's a and b, keeping its settings and re-picking the orientation; check_model points to it for reversed joints. - check_model reports boards that cut another in two (passes_through) and boards whose thickness does not match their material, and counts the joints that cut. - add_dimension can measure along an axis and returns length_mm and whether each end attached; its description no longer promises snapping. - The scene shows materials inherited from groups and only the joint settings each kind uses. - CLI: --brief keeps bounds and reading tools' answers; a failed batch shows the earlier results; group explains a part made from loose faces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Editing inside groups without enter_object, flip_joint, settings by kind, what "joints must not meet" means, rabbets with housed shelves, plinth and top joints, drawer proportions, lengthening notched boards with push_pull, tapered ladder uprights, dimensions (straight or along an axis, no snapping), outlines in vertical planes, arc radius, housed parts requested as components, and fixing problems the user did not mention. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- check_model returns passed (no errors or warnings); ok only says it ran. - Tools taking ids also accept a single "id". - When a joint cannot be cut, only joints whose region touches it are blamed; with none, the hint points at the board's own geometry (curves with many segments, vertices near the joint planes). - draw_polyline lists each new face with its center, so a split face's pieces can be told apart; get_object's description names center_mm. - Guide: odd thickness changes and shelf centres, drawer bottoms stopping short of the front, components keeping existing joints, ladder uprights with level cuts, splitting faces to lengthen notched boards, walls in the example room, backs behind dividers, chamfered tops, curve segment counts, and what to do when there is no one to ask. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… lack The guide said there were no chamfer tools; BenchUp has a Router and a Cutting Plan, which the tools do not expose yet. llms.txt now points agents to the benchup command and the agent guide, noting that it is built from source for now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 12, 2026
- Resolve "$N" references only in batches, and only text that is exactly a reference; "$12.50 hardware" stays as written. - Splice only referenced lists of ids into lists; a point stays one item. - MCP reloads the project before each call when it changed on disk, so a save in BenchUp no longer blocks the session. - check_model and get_cut_list use the assigned stock material, not the first one with the same name; the cut list shows the stock thickness. - Ignore bytes after IEND when reading or rewriting PNG projects. - New projects get the usual permissions under the umask. - Agent history entries use the translatable "Agent edit" label. - Windows: open projects through explorer.exe with a plain path, so no shell parses "&" or "%". - Read-only calls no longer copy the document; check_model evaluates joints once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
I reviewed this PR and fixed what came up in d6edc76: Bugs
Smaller fixes
New tests cover references, MCP after an outside save, same-named materials, trailing PNG bytes and permissions under the umask. 🤖 Generated with Claude Code |
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second PR from #13. It adds
benchup, a command-line tool that reads and edits.bupprojects from a shell or an AI coding agent, and serves the same tools over MCP. It builds onbenchup-toolsfrom #40, whose commits it also contains until that PR is merged.The CLI
Agent: ….--allow-sharedis passed."$1.created[0]".User documentation is in
docs/cli.md.docs/agent-guide.mdis compiled into the binary and printed bybenchup guide. A Claude Code skill is included incrates/benchup-cli/skill/.How it was shaped
I ran 12 furniture tasks four times with coding agents that knew only
benchup --help. The tasks included editing the example project, drawers with dovetails, a back in a rabbet, a curved bedside table, a leaning shelf, dimensions and cut lists. After each round, I fixed the tools and the guide. Across the 12 tasks:The remaining errors come from limits in the core, listed below. Agents now check their work with a dry run ending in
check_model.Per task: commands (errors) in each round
Example.bupThe shelf-component task cannot be done fully: a board inside a component instance cannot be joined to the sides outside it. The agents now explain this and offer an alternative.
The resulting changes to
benchup-tools:acarries the tenon or tongue,breceives it);add_jointpicks the woodworking orientation, validates the ranges the core uses, and refuses joints that cannot be cut, naming the joints a new one collides with;get_objecton a joint shows its settings and status;remove_jointandflip_jointtools;check_model: reports boards that cut another in two, overlaps without a joint (checked against the real solids), joints that cannot be cut or look reversed, thickness that does not match the material, open solids and loose geometry.get_cut_list,create_stock_material,move_toandget_guide.resize_boardtakes an anchor, andadd_dimensioncan measure along an axis.push_pullanddraw_polylinereturn the ids they create.enter_object.Changes outside the new crates
benchup-appnow usesbenchup_tools::filesfor the.bupformat. The format had been implemented twice, and the copies had drifted: the tools could not read the PNG previews the app now saves. The CLI keeps a file's container when saving.cargo check -p benchup-appis clean, and the app's project and desktop-file tests pass..github/workflows/pr.ymlruns the tests of both crates.site/llms.txtnow mentions the command, noting that it is built from source for now, and links to its documentation.Still to do
Testing
cargo test --locked -p benchup-tools -p benchup-clipasses: 49 tests in the tools and 17 in the CLI.🤖 Generated with Claude Code