Skip to main content
Glama

topopt

License: MIT Platforms: macOS (Apple silicon) and Linux x86_64 Python 3.13 Status: early

Install | Use | Examples | Documentation | License

It gives your AI agent a topology optimizer that sets itself up and runs on your own computer. The start part can be an STL file you already have, a sketch, a description in words, or a shape you work out with the agent in the chat: the rough form, where it is mounted and where the loads go, checked in a picture and changed until it is right. Then topopt runs the topology optimization: it finds a light shape that carries those loads and writes a smooth STL file that you can print.

More on the website: topopt.ai

Three ways to start a part:

  • An STL file that you have. "Here is bracket.stl. Keep the two screw holes, the tip carries 5 kg. Make it lighter."

  • A sketch and a few words. "I'm building a bike frame with 3D-printed lugs. Can the head tube lug be topology optimized?" With a sketch like this one:

  • Words only. "A wall hook for a T-shirt, two screws, 2 kg." Or a footbridge on two supports, or a stool that holds 100 kg.

A recorded run of a footbridge in the dashboard: a deck on two supports, the shape under it forms in 200 passes, then the finished bridge turns.

A footbridge on two supports: a recorded run (200 passes, 39 minutes with gpu-mg on an integrated GPU) in the dashboard replay.

Install

topopt works with any agent client that supports MCP servers. We test it most with Claude and recommend it, but topopt is not tied to Claude. topopt runs on a Mac with Apple silicon or on Linux x86_64, with at least 16 GB of memory for the example. You need no tool first: topopt uses your uv if you have one (uv 0.6.8 or newer); else the setup downloads a pinned uv release and checks its checksum.

What the setup downloads, and what topopt sends

  • uv 0.13.5, only if topopt finds no uv that it can use (18 MB, checked by its SHA256). Python 3.13 through uv (35 MB), the 55 packages of requirements.lock from PyPI, and setuptools (the setup builds the topopt code with it): about 200 MB in all, about 700 MB on disk. The sizes are from Linux x86_64.

  • After a plugin update, a complete setup links the code again offline. It downloads only when the lock file changed, and once when the Python of the launcher changes (the update to Python 3.13 downloads Python 3.13 and the packages again, about 180 MB, and needs the network).

  • topopt sends no data unless you allow it to send diagnostic data. A run, the dashboard server (127.0.0.1 only), the tools and the pages that open in your browser connect to nothing outside your computer, and they work offline.

  • The details, and how we checked them: What the setup downloads.

Clients

Claude Desktop is the most tested client and the one we recommend: the chat shows the pictures that topopt makes of your part.

  1. Download topopt.mcpb from the newest release (v0.5.0).

  2. Open the file with Claude Desktop.

  3. In a new chat, ask for the first example: "Run the topopt example examples/hook/hook.yaml and give me the dashboard link."

The first start sets up Python in the background: 1 to 3 minutes. Until then, the chat marks a topopt call as Failed: that is the setup status, not a fault. Everything else (the skills for the chat, the work folder field, problems): Claude Desktop.

The Code tab of Claude Desktop uses the Claude Code plugin: see Claude Code below.

This repo is a Claude Code plugin and also its marketplace. #latest is the newest release. In a terminal:

claude plugin marketplace add chartergroup/topopt#latest
claude plugin install topopt@topopt

Or in a Claude Code session:

/plugin marketplace add chartergroup/topopt#latest
/plugin install topopt@topopt

Then start Claude Code in your work folder and type:

/topopt:start-here

Claude checks the machine, helps you describe the part, checks the problem, starts the run and gives you the dashboard link (usually http://127.0.0.1:8765/). The first start sets up Python for the plugin: 1 to 3 minutes, about 200 MB (what it downloads). Until then, a topopt tool answers with the setup status.

In the Code tab of Claude Desktop, the plugin command opens Settings > Plugins. Add the plugin there:

  1. Open Settings > Plugins. Press + Add, choose Add marketplace, then Add from a repository.

  2. Type chartergroup/topopt#latest in the field URL and press Sync.

  3. Right after the sync, press Add on topopt: topology optimization for 3D printing. In the dialog about local MCP servers, press Continue.

  4. Start a session in a project folder and ask for the first example.

More: The Code tab: the plugin.

To update an install from #latest, run these in a terminal, then start a new session:

claude plugin marketplace update topopt
claude plugin update topopt@topopt

A pinned install updates another way: Update. Pinned releases, a checkout and first-run problems: Install the Claude Code plugin.

Every client starts the same server. Get a checkout and set it up once:

git clone https://github.com/chartergroup/topopt
cd topopt
sh scripts/topopt-env.sh sync

Then add the server to the MCP config of your client, with full paths (VS Code names the top key servers; Gemini CLI has no key type):

{
  "mcpServers": {
    "topopt-local": {
      "type": "stdio",
      "command": "sh",
      "args": ["/full/path/to/topopt/scripts/topopt-env.sh", "mcp"],
      "env": { "TOPOPT_WORKSPACE": "/full/path/to/topopt" }
    }
  }
}

If the tools do not show, run this in the checkout (about 2.5 s on Linux x86_64; it prints progress lines):

sh scripts/topopt-env.sh doctor

The setup, a JSON and a TOML config template, and the typical problems: the guide for any MCP client.

Other clients

For each client below, set up a checkout as in "Generic MCP client". The client facts have the dates.

Open the topopt folder in Cursor and enable the topopt MCP server of .cursor/mcp.json. In the one Mac test (2026-10-27) this server stayed Disabled, and a user entry in ~/.cursor/mcp.json worked (the entry).

Start codex in the topopt folder and trust the project when Codex asks. The project file .codex/config.toml starts the server. More: Codex CLI.

Put this in .vscode/mcp.json of the topopt folder, open the folder in VS Code and trust the workspace:

{
  "servers": {
    "topopt": {
      "type": "stdio",
      "command": "sh",
      "args": ["${workspaceFolder}/scripts/topopt-env.sh", "mcp"],
      "env": { "TOPOPT_WORKSPACE": "${workspaceFolder}" }
    }
  }
}

More: VS Code agent mode.

Put this in .gemini/settings.json of the topopt folder, start gemini there and trust the folder:

{
  "mcpServers": {
    "topopt": { "command": "sh", "args": ["scripts/topopt-env.sh", "mcp"] }
  }
}

More: Gemini CLI.

Related MCP server: cad-mcp

Use

With an agent client, ask in words. You can:

  • Bring or describe the part. One YAML file and one STL file for each region; the agent can write them from your words (The YAML format).

  • Check it. topopt check gives the grid size and a time estimate, and starts no run (Run a problem).

  • Run it and watch. The dashboard shows the shape, the volume and the compliance while the run goes (The dashboard). A recorded run plays again with --replay (Replay).

  • Run a fine pass. A finer voxel from the design of a finished run (Fine pass).

  • Check the print and the stress. Print checks and Verify the result.

  • Get the STL and the numbers. result/final.stl and result/metrics.json: mass, stiffness and run time (The final mesh).

  • Get pictures. Render.

In a client that shows MCP Apps, for example Claude Desktop, ask the agent to show the part in 3D: the chat shows the design space, the regions, an arrow for each load and the time estimate (the tool show_problem, see MCP server and its tools). The button "Start the run" in that view starts the run; the view then shows the pass and the volume every 5 seconds, and at the end a button "Discuss the result" gives the chat a message about the result (the host may put it into the chat input for you to send).

The T-shirt wall hook before and after the run, seen from the front and below: the design space with the fixed wall plate in blue and the load region in red, then the optimized hook that is 70 % lighter.

The hook: a full block of the design space would weigh 85.6 g. The part weighs 25.4 g (70 % less). The run took 133 s with gpu-mg on an integrated GPU.

Examples. The gallery shows each example part with a picture, the run and the mass. To run one, ask your agent, or in a checkout after Install: topopt run examples/hook/hook.yaml --out runs/hook.

Change a part with words. The hook prompt guide shows four prompts that change the hook example: two hooks at an angle on one base, three screws, a 2 kg jacket in place of a T-shirt, and a lighter part. Each prompt has its picture, the mass and the files to run it again.

The work folder is where topopt keeps your runs (runs/<name>/). How to change it for each client: The work folder.

Documentation

License

topopt is under the MIT license: see LICENSE. Third-party notices list the license of every package that topopt installs and of the third-party files in this repository.

Contributing

We recommend contributing with a coding agent. The instructions for agents are already in this repository, so open the folder in your agent and it finds what it needs by itself.

To contribute by hand, or to see the whole process (an issue first, a branch, a review by someone else, a person merges), read the contributing guide.

Available Tools

32 tools
apply_marksEdit the part at marksA
Destructive

Edit the finished part at the marks of the Refine page, in a NEW folder: facts and options, no verdict.

The run folder and final.stl stay as they are. No FE run is made: the stiffness and stress of the edited part are not known. Order: remove, then smooth, then add. A step that gives a part that is not closed, or that splits it, is rolled back, and the reply says why. The fixed, load and keep-out regions are frozen: an edit within frozen_keep_mm of them is clipped, and the clip is a fact. Reply keys: resource topopt://replies/apply_marks (the meaning of each key). marks: the path of marks.json (the Refine page exports it: version 1, mm, the frame of final.stl), its JSON text, or the marks object. radius_mm, amount_mm (the neck offset of add), strength (smooth) and mirror are used; a value that the page does not record is the pipeline value, named in defaults_used. A mark may carry smooth_mode or remove_mode (cleanup_list writes them); the order is per_mark, the mark, then the call option. run_dir: the run the marks belong to. Default: the last run of this server. Needs run.json, labels.bin and result/final.stl. out_dir: the new folder. Default: -marks beside the run folder. It gets edited.stl and apply_marks.json (the full report). Refused: a run folder or a folder inside one, a folder that holds an input file of the run, a symbolic link, a folder with files that is not an earlier apply_marks folder. allow_stale: apply the marks when source_sha256 of the marks file is not the hash of final.stl. Default: the reply states the fact (marks_match_final_stl false) and nothing changes. options: radius_scale (1.0), pitch_mm (node spacing of the crop box; default voxel size / 4, between 0.2 and 0.5), max_crop_voxels (8 million, a guard: above it the reply gives the facts and the options, e.g. pitch_mm). overwrite: write again into an earlier apply_marks folder. detail: the full report in the reply. Default: a short reply; apply_marks.json has the full report. yaml_path: the YAML of the run when run.json names a file that is not there; used for the exact frozen-region check. CONTRACTS.md section 29. Each mark is one local edit of result/final.stl on a signed distance field in a crop box around the mark, with the method of the pipeline stage s7_cleanup: remove = a cut that protects the parent (then the parent check), add = a closing with a ball (a neck offset when the closing adds little), smooth = an isotropic fairing for a point and a web fairing for a stroke (smooth_mode tube rebuilds a whole strut: it does not use radius_mm, and the reply gives its planned volume and reach). The new surface is spliced into the mesh in a zone around the edit; the triangles outside the zones stay bit for bit. More keys of options: max_total_voxels, frozen_keep_mm (3), frozen_full_mm (6), close_mm (3), neck_min_mm3, parent_tol_mm (0.2), parent_check ("report" or "enforce"), smooth_mode ("auto", "tube", "iso", "fair"), remove_mode ("cut" or "shave"), mirror_plane ({axis, at_mm}; else the plane of the mark or of run.json, else y = 0), skip ([mark ids]), per_mark ({id: {radius_mm, amount_mm, strength, mirror, smooth_mode, remove_mode, skip}}), check_frozen_exact, loose_body_mm3, max_odd_rays.

NameRequiredDescriptionDefault
marksYes
detailNo
optionsNo
out_dirNo
run_dirNo
overwriteNo
yaml_pathNo
allow_staleNo

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=false; the description then adds substantial behavior beyond that: invalid steps are rolled back with a stated reason, edits inside frozen_keep_mm are clipped and the clip is reported as a fact, splicing leaves triangles outside the edit zones bit-for-bit unchanged, allow_stale defaults to a no-op that only reports marks_match_final_stl false, and overwrite is required to reuse an earlier output folder. It also states that final.stl and the run folder are untouched, which is exactly the safety context the agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The first sentence front-loads the essential constraint (edit at marks, new folder, no verdict) and the reply-resource pointer is a useful shortcut. However, the body is a dense ~450-word block that interleaves parameter documentation with s7_cleanup method internals (closing balls, isotropic fairing, web fairing, tube rebuilds) in long parenthetical chains, making it hard for an agent to scan for the fields it needs. Every idea is relevant, but the packing and ordering cost readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must convey return behavior, and it does: it names the artifacts written (edited.stl, apply_marks.json), what the short vs detail reply contains, the reply resource topopt://replies/apply_marks for key meanings, and specific reply facts such as defaults_used, marks_match_final_stl, clip facts, and rollback reasons. It does not fully describe the shape of a successful short reply or the planned-volume/reach fields for tube smoothing, so a 4.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description carries the entire burden, and it does document all 8 parameters: marks (path, JSON text, or object; version 1, mm, frame of final.stl), run_dir defaulting to the last run with its required files, out_dir default and its refusal cases, overwrite, detail, allow_stale, yaml_path. The options object is expanded with defaults (radius_scale 1.0, pitch_mm bounds, max_crop_voxels, frozen_keep_mm 3, parent_check modes, smooth_mode/remove_mode enums, per_mark precedence). Several option keys (max_total_voxels, close_mm, neck_min_mm3, parent_tol_mm, loose_body_mm3, max_odd_rays) are listed without meaning, which keeps this from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: edit the finished part at the marks of the Refine page, into a NEW folder. It also draws a boundary against FE-oriented siblings ("No FE run is made") and names cleanup_list as the producer of marks, so the agent can place it in the workflow. It stops short of naming the sibling to use instead of this one, so not a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"No FE run is made: the stiffness and stress of the edited part are not known" tells the agent when this tool is and is not appropriate (i.e. it is not a substitute for run_topopt). It gives the step order (remove, then smooth, then add) and the refusal conditions for out_dir, which is usable guidance. There is no explicit "use this when X, use sibling Y instead" routing sentence, so a 4 rather than a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

build_regionsBuild regions from a specA
DestructiveIdempotent

Build region STLs and a problem YAML from a part spec given as data.

Use it when the user describes a part in words. Define the design space, fixed regions, loads (force vectors in N), keep-out regions (if any) and solid bodies (solid, forced solid). It already returns check and warnings. Call check_problem only after you edit the YAML, or for your own STLs. Next: state your assumptions, then run_topopt. If the user gave no load (no object, no mass and no force), ask before the run. A guard stop names an override: read the memory estimate against the RAM (a run above it can freeze the machine), raise the guard in the spec or take a larger voxel, and report what, why and the price. Writes /runs//. Reply keys: resource topopt://replies/build_regions (the meaning of each key). Use yaml_rel with run_topopt. On a wrong spec: {"ok": false, "error": one line that names the key path}. ok is false also when the builder fails (builder_ok false): problems gives the builder errors, and the files stay. name: folder and file name; default is spec["name"]. spec: a dict (or YAML text) with the schema of the part-to-topopt skill (spec.yaml): regions (design, fixed, load, solid, keep_out; primitives box, cylinder, sphere, capsule, bowl, prism, stl and screw_ring (see find_features), subtract), load_cases, material (E, nu, density or filament), settings (voxel_size may be "auto"; optional min_member_mm, filter_solid_neighbours, stop_rules (as in the YAML: a mapping turns the stop rules on, and time_budget_s, the user's own time budget, ends the run at the first pass after it; enabled: false keeps the rules off; the check warns when the estimate is above the budget) and perimeter_max_mm2: a bound on the surface area of the part in mm2). Units mm, N, MPa. settings.volume_fraction (default 0.25) is the mean density of the FREE design voxels; the fixed, load and solid voxels are solid on top. The YAML keeps your value. A mass in grams that the user asks for goes to settings.target_mass_g in place of volume_fraction (one of the two keys; both is an error): the engine derives the fraction from the grid. The report and derived.volume give the free and the forced-solid voxels, the target volume in mm3 and the target mass in g (the same numbers as check_problem). Loads: a force entry can also have moment in N mm and at in mm, and a case can have pressures of {region, value_mpa}. A fixed_axes mapping (fixed name -> axes) makes a roller of a fixed region. A springs list of {region, stiffness: [kx, ky, kz]} (N/mm, total; or stiffness_per_area) makes an elastic support on a load region; fixed may then be empty. A joints list of {region, to: [x, y, z], section: {kind: round, d: ..}} (mm; kinds round, tube, rect, props) bonds the faces of a load region to a rigid body and joins it with a beam to the fixed point to; fixed may then be empty. A flat face of a region whose plane is not on a voxel face (a voxel belongs to a region when its centre is inside) moves to the nearest voxel face. When such planes change the part, the report has ONE note: line (also in warnings) with the voxel size, the grid origin, an item for each plane (the region, the plane, larger or smaller than your shape) and the options. check.region_planes has all planes, with offsets in mm and voxels, and changes_part (false when the layer is under a region of higher priority or outside the part). Items in one region join (union). Optional spec key mirror: a list of up to 3 axis-aligned planes with distinct axes, each {normal: x|y|z, at_mm: }, align: auto|face|centre optional. The tools return facts about it (parity, orphans, load asymmetry).

NameRequiredDescriptionDefault
nameNo
specYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the annotations: writes to <work folder>/runs/<name>/, returns check and warnings itself, leaves files on builder failure with problems listing the errors, error shape is {ok:false, error} naming the key path, and a guard stop can freeze the machine if the memory estimate exceeds RAM. The idempotent/destructive hints are consistent with a spec-to-files build.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and usage are front-loaded, but the body is a dense wall of run-on sentences mixing tool behavior with exhaustive spec-schema detail (voxel-plane notes, mirror parity, spring stiffness units). Much of that content earns its place given 0% schema coverage, yet its organization makes it hard to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex spec-driven builder with no output schema, the description covers inputs, side effects, result keys, error shapes, guard-stop handling, and where further detail lives (topopt://replies/build_regions, spec.yaml). Nothing an agent needs in order to call it correctly appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description carries the full burden and does: it documents the `name` default (spec["name"]) and expands `spec` in depth — regions, primitives, load_cases, material, settings, units (mm, N, MPa), volume_fraction vs target_mass_g mutual exclusion, mirror/springs/joints/fixed_axes. An agent could construct a valid spec from this text alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb and two concrete artifacts ('Build region STLs and a problem YAML from a part spec given as data'), and the second sentence pins down the triggering condition (user describes a part in words). Named siblings (check_problem, run_topopt, find_features) make its position in the pipeline unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing: use it when the part is described in words, call check_problem only after editing the YAML or for the agent's own STLs, then state assumptions and go to run_topopt. It also gives a decision rule for missing load data (ask before the run) and a recovery procedure for a guard stop.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

case_statusShow case statusA
Read-onlyIdempotent

Show the case of a problem YAML: the brief, the input hashes, the earlier runs and what is stale. Changes nothing.

brief_stated is true when a current brief is recorded. stale_files names the files that changed since the brief. A change of a comment, of the format or of a method setting (for example settings.solver) in the YAML is a fact, not stale. inputs has the SHA-256 of the YAML and of each region file now. runs lists the runs that run_topopt started for this case, newest first. Each has its state (read from the run folder), stale and stale_files for its own inputs (a run is stale after any change of the YAML content, a method setting too), and facts, for example that the folder now holds another run. gate says what run_topopt does now.

yaml_path: the problem YAML (relative paths start at the work folder).

NameRequiredDescriptionDefault
yaml_pathYes

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/idempotent/non-destructive annotations, the description explains nuanced behavior: what counts as stale, that comment/format/method-setting changes are facts rather than staleness, how run staleness differs, and what gate means. This gives an agent substantial context for interpreting results correctly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first sentence, and the remaining detail is dense but relevant to interpreting the returned status fields. It is appropriately sized for a status tool with no output schema, though the second paragraph is quite packed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must explain the return semantics, and it does: brief_stated, stale_files, inputs, runs, per-run stale state, and gate are all defined with enough context to interpret them. For a complex case-status tool, this is complete enough for an agent to call and understand it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must carry parameter meaning. It identifies yaml_path as the problem YAML and adds the important path-resolution rule that relative paths start at the work folder, which is meaningful beyond the bare string schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence gives a specific verb and resource: shows the status of a problem YAML case, including brief, input hashes, earlier runs, and staleness. It explicitly says it changes nothing, and the scope is clearly case-level rather than run-level, distinguishing it from siblings like run_status.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when this is useful by enumerating case-level status fields and noting that it changes nothing, but it does not explicitly say when to use this instead of run_status, show_problem, or other status tools. Usage is inferable but not routed with alternatives or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_problemCheck a problem YAMLA
Read-onlyIdempotent

Load and voxelize a problem YAML (no optimizer run; with settings.solver auto it runs the short self-test of gpu-mg in a child process, at most 60 s: seconds the first time on a device and driver, then the cached pass). Returns facts, estimates and warnings.

Use it before run_topopt, also for your own YAML and STLs. Read the facts and tell the user the numbers that matter. Resource topopt://levers: the key for a symptom of these facts, and the price of a try. yaml_path: the problem YAML (relative paths start at the work folder). Another solver: settings.solver (auto, cholesky, pardiso, amg, gpu-mg) or --solver of topopt run and check, not of run_topopt. For gpu-mg, settings.gpu_device (auto, a number from topopt check, or a part of the name). Warnings are facts; a warning that starts with "settings.solver is" (the solver cannot run here) means run_topopt will stop with the same message. A warning that starts with "fact: settings.iterations" says that the passes end before the last stage of settings.beta_schedule (a grey design): it gives the options (iterations, or the schedule scaled to the passes) and the measured price. It does not block the run. On a wrong input: {"ok": false, "error": ...}. Reply keys: resource topopt://replies/check_problem (the meaning of each key). A settings.perimeter_max_mm2 below the smallest possible perimeter gives {"ok": false, "error": ...} with the options. The reply key lost_force has, for each load case, the total force, the force on nodes that are also fixed (the solver drops it) and the lost percent. Key fine_pass: the voxel that the part needs (voxel_mm, one value; recommend; limiting: the feature that sets it, its thickness and the voxels across now and needed; and with recommend the fact line). run_topopt with fine_pass=true or fine_from runs a fine pass.

NameRequiredDescriptionDefault
yaml_pathYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial context beyond the readOnly/idempotent annotations: the auto-solver path spawns a child process for a self-test bounded at 60 s (longer the first time per device/driver, then cached), and it distinguishes blocking warnings ('settings.solver is' → run_topopt will stop) from non-blocking ones ('fact: settings.iterations' → grey design, not blocking). Error shape on bad input is disclosed. The account of caching and child-process cost is slightly garbled, so not a clean 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, which is good, but the body sprawls across loosely related topics (solver selection, warning prefixes, reply keys, fine_pass internals) with at least one malformed sentence ('seconds the first time on a device and driver'). Length is partly justified by the tool's complexity, but the structure does not help an agent scan it.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema, and the description does cover the return shape at a high level (facts, estimates, warnings; ok:false + error), plus specific keys it knows matter (lost_force, fine_pass). It delegates full reply-key meaning to topopt://replies/check_problem, which is a reasonable pointer but leaves the description alone insufficient for interpreting the payload.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter has 0% schema description coverage, but the description supplies the semantics that matter: yaml_path is the problem YAML and relative paths resolve against the work folder. That is exactly the ambiguity an agent would otherwise hit. The surrounding solver/GPU settings discussed are YAML keys, not parameters, which adds a bit of noise.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb chain and resource: 'Load and voxelize a problem YAML', and immediately scopes it with 'no optimizer run'. The sibling boundary with run_topopt is drawn explicitly ('Use it before run_topopt'), so an agent can pick between validating and running without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear workflow placement: call it before run_topopt, and it is also valid for the user's own YAML and STLs. It clarifies that settings.solver is not a run_topopt parameter, which prevents a real misuse. No explicit 'do not use when' case is stated, keeping it below a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cleanup_listList cleanup candidatesA
Destructive

List the geometric cleanup candidates of a finished part as a marks file, in a NEW folder: facts and options, no edit, no verdict.

CONTRACTS.md section 29.3. The tool scans result/final.stl with the detectors of the pipeline stage s7_cleanup and writes marks.json (format 1, mm: apply_marks, the Refine page and the marks: source of ratchet_run read it) and cleanup.json (the full report). It lists loose bodies (no fixed and no load voxel), dead-end spurs, thin bumps, uneven struts (SMOOTH) and flat webs (FAIR). When a loose body exists the file holds the bodies only: judge them, then list the acc_01 of that ratchet root for the features. The list judges nothing: ratchet_run(marks=marks_rel) applies each mark and judges it with the rules of the YAML. The run folder and every input stay as they are. Time: about 2 s on the short hook and 8 s on the ladle. The call runs in the server and finishes if the client stops waiting (Codex waits 60 s for a tool by default); then read cleanup.json, or call again with overwrite=true. A grid above max_voxels or the memory limit gives the facts and the options (pitch_mm, max_gb), not a crash. A wrong input gives {"ok": false, "error": ...}. run_dir: a finished run, or an acc_NN folder of a ratchet root (needs run.json, labels.bin, result/final.stl). Default: the last run of this server. out_dir: the new folder. Default: -cleanup beside the run folder (beside the root for an acc_NN folder). Refused, with the reason and the options: a run folder or a folder inside one, a ratchet root or a folder inside one, a folder with an input file, a symbolic link, a folder with files that is not an earlier cleanup folder. estimate_only: the memory and time estimate of the detector and the judge; no search, no file. options: pitch_mm (0.5), max_candidates (10; null lists all), kinds (body, spur, bump, member), order ("pipeline" or "stress"), max_voxels, max_gb, and the limits of the detectors (spur_*, bump_*, member_*, mild_*, web_flatness, opening_radius_mm, frozen_near_mm, frozen_max_share, near_frozen_mm); cleanup.json gives each default and its source line in the pipeline. The constants of the method are not settable. overwrite: write again into an earlier cleanup folder. detail: the full report in the reply. yaml_path: the YAML of the run when run.json names a file that is not there. root: a ratchet root; its log gives the measured judge time for the estimate. Each mark has the detector, the location, the operator, the thresholds used, the measured sizes and, when verify/fields.npz is there, the stress near it. The facts also say how well the detectors fit this part (applicability). Reply keys: ok, counts, candidates (id, type, operator, detector, confidence, centre_mm, detected_volume_mm3, length_mm, nearest_frozen_mm, stress_ratio, mirror), applicability, bodies, estimate, routes, problems, notes, out_dir_rel, marks_rel, report_rel.

NameRequiredDescriptionDefault
rootNo
detailNo
optionsNo
out_dirNo
run_dirNo
overwriteNo
yaml_pathNo
estimate_onlyNo

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only flag destructive=non-idempotent write; the description adds a great deal more: it writes marks.json and cleanup.json into a brand-new folder, never touches the run folder or inputs, and refuses existing/ratchet-root/symlink/non-cleanup folders with the reason and options. It also discloses runtime (~2 s / 8 s), that the call completes server-side even if the client stops waiting (Codex 60 s), recovery via cleanup.json or overwrite=true, the memory/voxel-limit fallback instead of a crash, and the error envelope {'ok': false, 'error': ...}.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and the safety-critical refusal rules are front-loaded, and nearly every line carries real information (defaults, reply keys, recovery paths). But the body is a wall of telegraphic fragments and parentheticals ('CONTRACTS.md section 29.3', 'the marks: source of ratchet_run read it'), with no headings or grouping, so parameter facts, detector lists and failure modes interleave and are hard to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, yet the description enumerates the reply keys (ok, counts, candidates with their fields, applicability, bodies, estimate, routes, problems, notes, out_dir_rel, marks_rel, report_rel) and the error shape. For a destructive, write-producing tool with 8 undocumented parameters, it covers everything an agent needs to call it safely and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must carry all semantics — and it does, documenting every one of the 8 parameters: run_dir and its default (last run of this server), out_dir and its default plus the refusal cases, estimate_only, overwrite, detail, yaml_path, root, and the full options set with defaults (pitch_mm 0.5, max_candidates 10/null, kinds, order, max_voxels, max_gb, spur_*/bump_*/member_*/mild_*, web_flatness, opening_radius_mm, frozen_*). It even notes which constants are not settable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a specific verb, resource and artefact: list geometric cleanup candidates of a finished part as a marks file in a NEW folder. It explicitly separates itself from siblings by stating 'The list judges nothing: ratchet_run(marks=marks_rel) applies each mark and judges it' and by naming the marks format consumed by apply_marks/the Refine page. An agent can tell this apart from ratchet_run and apply_marks without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states the precondition (a finished run needing run.json, labels.bin, result/final.stl), the branch where a loose body exists ('judge them, then list the acc_01 of that ratchet root'), the follow-up tool (ratchet_run with marks_rel), and a cheap pre-flight mode (estimate_only: no search, no file). What it lacks is a crisp 'do not call this when…' list, and the guidance is embedded in dense prose rather than stated as routing rules.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

compare_runsCompare runsA
Read-onlyIdempotent

Runs side by side: two runs (setup diff and metrics diff), or a base with its variants (one table). Reads files, writes nothing.

Give one form. (run_a, run_b): A is the base and B the change; delta is B - A. Every value names its source: run.json (what each run recorded at its start: the YAML path and the region file names, no hash), labels.bin, the YAML and STL files on disk (read now), and result/metrics.json. So the files on disk can be newer than the run or can differ from it; inputs says so as facts (a newer YAML or STL, YAML values that differ from run.json, labels from the files on disk that differ from labels.bin). The facts are evidence, not proof. (run_a, variants): run_a is the base; variants is a list of run folders, any number. One row per run, the base first.

run_a: the base run folder (relative paths start at the work folder). run_b: the changed run folder (two-run form). variants: the run folders of the table (table form); not together with run_b. check_labels: voxelize the YAML on disk and compare it with labels.bin (a few seconds on a big grid). null: do it when the grid has at most 10 million voxels. true: any grid size. false: skip it. Two-run keys: a, b, setup (run_json_diff, yaml_diff, region_files with the STL hashes, labels_diff: the voxel classes that changed, with the box in mm), metrics (rows with a, b, delta, delta_pct; stiffness per case; filter facts), inputs, notes (for example: the load cases differ, so compliance is not comparable), summary and problems. Table keys: base; runs (state, mass_final_g, mass_saved_pct, stiffness per load case from the optimizer, verdict, verify: done, not run or no result, print: a few print facts, render: the path of the newest montage PNG on disk, or null); vs_base (the setup diff of each variant against the base); notes; summary; problems. A fact that no file holds is null and an entry in problems. The table makes no image: render_part does. On a wrong call or folder: {"ok": false, "error": ...}.

NameRequiredDescriptionDefault
run_aYes
run_bNo
variantsNo
check_labelsNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the read-only annotations, it discloses important behavior: it reads files and writes nothing, files on disk can be newer than or differ from a run, the reported facts are evidence rather than proof, and check_labels can cost seconds on a large grid with null meaning a 10-million-voxel threshold. It also describes the return shape and error behavior, which matters because there is no output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the two forms and the core read-only behavior, and most of its detail is useful for a complex comparison tool. It is dense and long, with some output-key detail that could be tightened, but it is not padded with empty boilerplate.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, four parameters, and complex comparison logic, the description supplies the missing context: both call forms, parameter behavior, data-provenance caveats, output keys for each form, null handling, problems reporting, and error behavior. An agent has enough information to choose a form and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must carry parameter meaning, and it does: run_a is the base, run_b is the changed run in two-run form, variants is a list of run folders in table form, and check_labels has explicit null/true/false semantics. It also clarifies that relative paths start at the work folder and that run_b and variants are mutually exclusive.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: compare two runs side by side, in either a two-run diff form or a base-plus-variants table form. It also distinguishes the tool from render_part by noting that the table makes no image, so an agent can tell what this tool does and does not do.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly explains the two call forms and warns that run_b and variants should not be used together, which is strong usage guidance. It also points to render_part for images, but it does not explicitly compare itself with several nearby siblings such as run_result, run_history, or list_runs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

environmentCheck this machineB
Idempotent

Facts about this machine and the solver backends. Changes nothing.

Use it to answer "can this machine run it, and how fast?", or before a long run. Tell the user the numbers that matter. yaml_path: optional problem YAML (relative paths start at the work folder). With it, problem holds the time estimate for each backend (model values, not promises). Reply keys: resource topopt://replies/environment (the meaning of each key). If TOPOPT_PYTHON names another Python, the data is for that Python (run_interpreter says so). recommendations are offers as data: when a faster backend is possible but not installed (pypardiso on Linux x86_64, the Accelerate shim on a Mac), each has a reason, the command and license_note (speedup_factor when it is measured). This tool installs and builds nothing. If the user agrees, you run the command. Say the reason (and the speed-up) first. gpu_solver is a fact, not an offer. auto takes a GPU that passes a short self-test, and goes on with the CPU solver (auto_choice.cpu_solver) from the last checkpoint if gpu-mg fails during a run. settings.solver: gpu-mg asks for it on any OpenCL device (run_topopt has no solver argument: write it in the YAML) and has no fallback. The OpenCL device list and the self-test run in a child process (limit 60 s). At the limit opencl.problem says so, and auto takes the CPU rule; TOPOPT_AUTO_GPU=0 skips the wait. A gpu-mg run that stops with "did not reach the relative residual" lists its options in the error (settings.gpu_tol, settings.gpu_backward_error, settings.gpu_max_iter in case B, a stiffer start design, another solver); the residual history is in gpu_mg.jsonl of the run folder. gpu-mg takes springs, joints and per-axis supports (a fixed entry with axes), alone or together. In case C (no 64-bit float on the device) the joint term is computed in 32-bit float and the inner PCG removes the rigid modes of each body and 6 harmonic columns for each bonded patch, and solves them in 64-bit on the host: check prints the beam over the bond stiffness with the cases that were measured on pocl and on one Intel Arc iGPU (one host each; revision 133e5a1; a cube that only a joint holds solved at 9.9e-12 and above with the rigid modes removed, and at 3.3e-7 and above without; a part with two tube joints and no fixed region solved with the harmonic columns and stopped without them) and the memory of the columns, which the memory estimate does not count. These are facts, not a limit. A run that stops gives the ratio and the options (another solver, gpu_case B on a device with 64-bit float, a stiffer beam).

NameRequiredDescriptionDefault
yaml_pathNo

TDQS

B3.1/5.0
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description flatly asserts "Changes nothing" and "installs and builds nothing", while the annotations declare readOnlyHint=false. It also discloses that the OpenCL device list and self-test run in a child process with a 60 s limit, an action with real cost that the 'changes nothing' framing hides from an agent deciding whether to auto-approve. The rest of the disclosure (gpu-mg failure modes, case C behavior, env vars) is rich but does not cure this conflict.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The first three lines are well front-loaded, but the remainder is a wall of deep solver internals — pocl and Intel Arc measurements, revision 133e5a1, residual values, harmonic columns, gpu_tol/gpu_backward_error tuning — that an agent does not need in order to call this tool or read its reply. Much of it reads as release notes rather than tool guidance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description does try to cover returns: reply key resource, the meaning of `recommendations` (reason, command, license_note, speedup_factor), and the distinction between a fact (`gpu_solver`) and an offer. But it never states the actual shape of the top-level reply or the units/format of the time estimates, and the bulk of the text is tangential to correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the single parameter is bare in the schema, so the description must carry it — and it does: yaml_path is optional, relative paths resolve from the work folder, and passing it changes the reply so `problem` holds per-backend time estimates. That is meaningful semantics beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening line states a specific resource and scope: facts about this machine and the solver backends, with an explicit "Changes nothing" non-goal, reinforced by "Use it to answer 'can this machine run it, and how fast?'". It is clearly distinct from problem-oriented siblings such as check_problem/show_problem, though it never names them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives two concrete triggers (answering 'can this machine run it, and how fast?' and 'before a long run') plus a negative boundary ('installs and builds nothing ... if the user agrees, you run the command'), which is a real routing rule. It never names an alternative sibling for the case where the user wants a specific problem validated instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

export_stepExport a STEP fileA
DestructiveIdempotent

Write a faceted STEP file of a finished run (extra step: OpenCASCADE). Post-only: no pass runs and no input file changes. Same as topopt step.

The call is synchronous: it returns when the file is written, and a large export holds the call for minutes. Call it with estimate_only first for a large mesh: the estimate gives the time before the work starts. Cost (Linux x86_64): the cost follows the number of faces after the simplification, and that follows the part. A hook gives 9,000 to 36,000 faces with the default tolerance: 10 to 40 MB, 12 to 40 s, about 1 GB. A larger part with 85,000 faces took 102 s and 1.8 GB; another with 356,000 faces took 613 s (10 minutes) and 5.8 GB, and the file was 402 MB. tolerance_mm=0 keeps every triangle: about 1.1 KB, 1 ms and 16 KB of memory for each triangle (322,000 triangles: 363 MB, 6 minutes, 5.5 GB). run_dir: the run folder (relative paths start at the work folder; default: the last run). It wraps result/final.stl, or result/part_only.stl with part_only. Output: result/final.step (result/part_only.step) and its report next to it, result/final.step.json (result/part_only.step.json). out is another file path or an existing folder; the report is then next to that file (.json), so the run folder gets no file. An existing file is replaced only when it is a .step or .stp file; the input STL and any other existing file give an error with the options. estimate_only: simplify, count the faces and estimate size, time and memory; nothing is written. It works without OpenCASCADE. A failed check is a fact and the file is still written (exit_code 3). Without the extra the reply is {"ok": false, "missing_extra": "step", "install_command": ..., "error": ...}. Any other failure is {"ok": false, "error": ..., "exit_code": ...}. tolerance_mm: the simplification of the mesh (manifold3d), the largest move of the surface in mm; 0 = none. Default: the voxel size of the run / 20 (0 when the run folder holds no voxel size). A larger value gives fewer faces and a smaller, faster file; a value that removes every triangle is an error and no file is written. merge_planes: coplanar faces join into one planar face (the frozen plates). schema: AP214 (default) or AP242 (ap-242 and ap242 also work). The faces are the facets of the mesh, so a CAD program can cut holes in the solid and join it to other parts; it cannot edit the surfaces. The reply is the report: input (triangles, volume), settings (tolerance_mm and where it comes from), simplify, merge_planes, build (bodies, voids, and the check of the model in memory), model (the file read back: solids, faces, edges), volume (STEP against STL), deviation (sampled distance in both directions: max and mean, in mm), checks (read_back, topology, before_write, valid_solid, closed, units, schema: pass or fail with a reason; none has a threshold), checks_failed, options, timing_s, peak_rss_bytes. The reply of any other failure has the first line of stdout when there is one, and "signal" when the child process was killed.

NameRequiredDescriptionDefault
outNo
schemaNoAP214
run_dirNo
part_onlyNo
merge_planesNo
tolerance_mmNo
estimate_onlyNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare mutation, non-idempotent-looking write, and destructive=true, but the description adds far more: the call is synchronous and can block for minutes, concrete cost ranges in faces/MB/seconds/RAM, the fact that an existing .step/.stp is replaced while other existing files error, and that a failed check still writes the file with exit_code 3. These are behavioral facts an agent cannot derive from the annotations or schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and scope, and nearly every sentence carries operational information. The cost paragraph is somewhat over-detailed—three separate benchmark anecdotes (9k–36k faces, 85k faces, 356k faces) could be compressed to a range plus the note that cost scales with face count—which costs some scannability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by enumerating the report fields (input, settings, build, model, volume, deviation, checks, timing_s, peak_rss_bytes) plus the two failure reply shapes. Combined with 7 fully explained parameters and the cost model, an agent has everything needed to invoke, budget, and interpret this tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the entire burden and does: it defines run_dir defaults and path resolution, out semantics and where the report lands, part_only's effect on input/output filenames, tolerance_mm's meaning (largest surface move in mm), its default derivation (voxel size / 20), and its edge case (removing every triangle is an error), plus merge_planes and schema (AP214/AP242 aliases) and estimate_only.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource ("Write a faceted STEP file of a finished run") plus an explicit scope restriction ("Post-only: no pass runs and no input file changes") and a CLI equivalence ("Same as `topopt step`"). An agent can distinguish this from a STL/other-format export or from run_mesh/verify_run siblings without reading the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit recommended workflow ("Call it with estimate_only first for a large mesh") with the reason (the estimate gives time before work starts), states the precondition (a finished, post-processing run), and states exclusions (no pass runs, no input file changes, existing non-.step files give an error). That is when-to-use, when-not-to-use, and a prerequisite in one place.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_featuresFind holes and faces of an STLA
Read-onlyIdempotent

List the holes, bosses and flat faces of an STL file, in mm. Read only: the file is read and nothing is written (CONTRACTS.md section 45).

stl_path: an STL file (a relative path starts at the work folder). About 4 s for a million triangles. A wrong input gives {"ok": false, "error": ...}. A hole's point, axis, radius_mm and length_mm are the keys of a bore in interfaces (section 23). holes: each cylindrical hole has id, point (the centre of the first end face), the unit axis, radius_mm, length_mm, end_point, depth (through, blind, closed or unknown), ends, arc_deg (the angle the wall covers), segments and chord_sag_mm (the facets lie that far inside the radius), fit (distance of the wall vertices to the circle) and coaxial_with (a stepped hole is two cylinders on one axis). Every hole is listed with its radius and fit, whatever its size. bosses: convex cylinders (a shaft, a post), the same keys without depth. flat_faces: planar regions, the largest first: normal (outward, unit), area_mm2, centroid, offset_mm. mesh: faces, watertight, bounds_mm. A mesh that is not closed still gives what can be found (no repair). method: numbers (each detection number as used) and counts. facts: plain sentences (an open mesh, a stepped hole, a feature near a limit, regions left out). A hole whose wall joins a fillet, a tapered hole and a slot are not cylinders to this method. Your STL as a region item of build_regions: {stl: {path: part.stl, plug_holes: [H1] or all, screw_holes: [H2] or all, ring_mm: 2}} (a relative path starts at the work folder; a growth box is one more item). Only a closed solid mesh is read (no repair). plug_holes fills those holes (ids stable for one file). screw_holes adds a frozen ring round each: t = 0.5 x d, at least 2 voxels, or ring_mm (a number, or {H2: 2}). {screw_ring: {path: part.stl, hole: H2}} is that ring as a fixed or load region. A mouth chamfer and a drill point stay.

NameRequiredDescriptionDefault
stl_pathYes

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by detailing return structure (holes, bosses, flat_faces, mesh, method, facts), timing, error format, limitations (open mesh still returns what can be found, no repair), and the exact integration with build_regions. This is rich behavioral context that helps an agent understand what to expect.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a long, dense block of text with many technical details and references to external documentation (CONTRACTS.md sections). While the information is useful, it is not front-loaded or well-segmented, making it harder to scan quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of the output and the absence of an output schema, the description thoroughly explains all return fields, error behavior, and usage in downstream tools. It leaves little ambiguity about what the tool does and how to interpret its results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter stl_path has no schema description, but the description compensates by explaining that a relative path starts at the work folder and that it must be an STL file. This is sufficient for a 1-param tool, though not extensive enough for a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'List the holes, bosses and flat faces of an STL file'. This clearly distinguishes it from all sibling tools, which deal with runs, regions, materials, etc., not feature extraction from an STL.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context: it is read-only, mentions the time cost for a million triangles, describes error behavior, and explains how the output is used with build_regions. It also notes limitations (fillet-joined, tapered holes, slots are not detected) but does not explicitly state when to prefer it over alternatives—though none exist among siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_materialFind a filamentA
Read-onlyIdempotent

Find a 3D printing filament by name in the catalog that ships with topopt and in the user filaments of the work folder (topopt-filaments.yaml). It reads; it changes nothing.

The user only names the filament; the tool knows the numbers of the data sheet. Use it when the user says which spool they have ("Bambu PLA Basic", "Prusament PETG"), before you ask for a modulus or a density. name: the product as the user says it. Case, punctuation, the maker name and the word "my" do not matter ("polylite abs" and "Polymaker PolyLite ABS" are one filament). A family alone ("PLA", "PETG") names no product: the answer is "ambiguous" with every filament of the family. Returns: ok, status, query, catalog_version, matched_by, origin, profile, derives, candidates, differs, suggestions, makers, user_file, note.

  • "match": profile is the filament: id, name, family, sheet_version, the tensile modulus and strength in the layer plane (xy) and across the layers (z), density, temperatures, enclosure, hardened nozzle, drying, and the source of the values (source_url, opened, tag, field_sources, note). A value that no source states is null (unknown): say so. nu is null for every filament, because no data sheet gives it. derives says what material.filament: <id> sets in a run (E is the lower of the XY and Z modulus, taken from the bending modulus of the sheet when the sheet gives no tensile modulus; density is the one of the sheet, the middle of a range that the sheet gives, or else the median of the filaments of the family, labelled assumed; nu stays the assumed 0.35; a key in the YAML wins) and what the profile cannot give.

  • "ambiguous": candidates and differs (the facts on which they differ). Ask the user which one; do not pick for them.

  • "none": suggestions ("did you mean": never taken by itself) and a note on how to go on: look up the maker data sheet and save_material the values, or ask the user. The numbers of a data sheet describe printed test bars of one maker and one set of print settings, not the part of the user. user_file: path, exists, entries, problems. A problem in the file is a fact; the shipped catalog still works. Next: show the user the derived values. printer_materials shows what the printer of the user can print; check_problem gives the same fit for a YAML with material.filament, in its key material. save_preferences(material={"filament": id}) keeps the filament, or write material: {filament: <id>} in the YAML.

NameRequiredDescriptionDefault
nameYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare read-only, non-destructive behavior, but the description adds substantial behavioral context: case/punctuation/maker-name normalization, ambiguous-family handling, `user_file` problem isolation, null-value semantics, derivation rules for `material.filament`, and the caveat that data-sheet values describe printed test bars rather than the user's part. No annotation contradiction is present.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition is front-loaded with purpose and usage, and most content earns its place because there is no output schema and the return statuses are complex. It is still dense prose for a one-parameter lookup, with a long inline listing of return fields that could be more scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema and a single undocumented parameter, the description supplies the missing return semantics, statuses, derived-value behavior, user-file behavior, and follow-up tool guidance. Together with annotations covering safety, an agent has enough information to call and interpret the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage for the single `name` parameter, so the description must carry the full burden, and it does. It explains that the product is taken as the user says it, that case, punctuation, maker name and 'my' do not matter, and that a family alone yields an 'ambiguous' result.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: it finds a 3D printing filament by name in the shipped catalog and the user's `topopt-filaments.yaml`. It also distinguishes the tool from write operations by saying 'It reads; it changes nothing' and later names related tools such as `save_material`, `printer_materials`, and `check_problem`.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit trigger: 'Use it when the user says which spool they have ... before you ask for a modulus or a density.' It also explains what to do on ambiguity ('Ask the user which one; do not pick for them') and on no match (look up the data sheet and `save_material`, or ask the user), so when-to-use and next alternatives are clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_printerFind a 3D printerA
Read-onlyIdempotent

Find a 3D printer by name in the catalog that ships with topopt and in the user printers of the work folder (topopt-printers.yaml). It reads; it changes nothing.

The user only names the printer; the tool knows the print parameters. Use it when the user says which printer they have ("Bambu P1S", "my Prusa MK4S"), before you ask for a bed size or a process. name: the model as the user says it. Case, punctuation, the maker name and the words "my" and "printer" do not matter ("p1s", "Bambu Lab P1S" and "bambu p1 s" are one printer). Returns: ok, status, query, catalog_version, matched_by, origin, profile, derives, candidates, differs, suggestions, vendors, user_file, note.

  • "match": profile is the printer: id, name, origin (catalog or user), bed_mm, build_height_mm, nozzle, temperatures, enclosure, nozzle material, extruder, and the source of the values (source_url, opened, tag, field_sources, note). A value that the source does not give is null (unknown): say so. derives says what print.printer_model: <id> sets in a run (the bed and the printer type, when the YAML does not give them) and what the profile cannot give.

  • "ambiguous": candidates and differs (the facts on which they differ). Ask the user which one; do not pick for them. matched_by is "partial" when the text is only a part of a name (one candidate too: a similar model can have other numbers).

  • "none": suggestions ("did you mean": never taken by itself) and a note on how to go on: look up the maker page and save_printer the values, or ask the user. user_file: path, exists, entries, problems. A problem in the file is a fact; the shipped catalog still works. Next: show the user the derived values, then save_preferences(print={"printer_model": id}) keeps the printer, or write print: {printer_model: <id>} in the YAML. A bed_mm or printer_type in the YAML wins. With a printer, the print report also compares the part height with its build height.

NameRequiredDescriptionDefault
nameYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly and idempotent annotations, it discloses matching behavior, how ambiguous and no-match cases are returned, what to do when the user file has problems, and how the shipped catalog remains usable. This is unusually rich behavioral context for an agent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose, usage, and parameter semantics before detailing return behavior. It is lengthy, but most detail is justified because there is no output schema; the return field inventory and profile field explanation are dense but useful.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter tool with no output schema, the description covers matching semantics, all three result modes, user-file edge cases, and recommended next steps. An agent has enough information to call it correctly and interpret the response.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden for the single name parameter. It explains that the name is the model as the user says it, that case, punctuation, maker name, 'my' and 'printer' are ignored, and gives concrete equivalent examples.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Find a 3D printer by name' in both the shipped catalog and the work folder's user printers file. It also explicitly says the tool only reads and changes nothing, which separates it from mutation-oriented siblings such as save_printer.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a clear trigger: use this when the user names their printer, before asking for bed size or process. It does not explicitly state when not to use it or name a competing lookup alternative, but the usage context is strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_runsList runsA
Read-onlyIdempotent

List the run folders in the work folder (newest first), with state and iteration.

A run folder is any folder in the work folder, or in its runs/ folder, that holds status.json or run.json. Paths are relative to the work folder.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the description's job is to add operational detail — and it does: result ordering (newest first), the fields surfaced (state and iteration), and the exact criterion that makes a folder a run. It stops short of describing the full return shape or what happens with an empty/nonexistent work folder.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the action and ordering, followed by the one definition an agent actually needs. No filler or restatement of the name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must convey the return content, and it names the salient fields (state, iteration) and ordering. A little more on the record shape (e.g. whether the folder name/path is included) would make it fully self-sufficient for a zero-param listing tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4. The description still adds useful framing by clarifying that any paths in the results are relative to the work folder, which preempts a likely agent misreading.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List the run folders in the work folder') and then defines the ambiguous term 'run folder' by its detection criterion (status.json or run.json). An agent can tell this apart from run_status, run_result, or run_history without opening any schema, since this is the enumeration tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The ordering note ('newest first') and the folder-detection rule imply the discovery use case, but the description never says when to choose this over siblings like run_history, run_status, or compare_runs. Usage is inferable rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marks_to_hintsTurn marks into hintsA
Destructive

Turn the marks of the Refine page into facts, options and a proposed YAML in a NEW folder. Edits no mesh.

A mark is a point of emphasis, not an absolute. The report gives, for each mark, the facts (position, radius, distance to the surface of final.stl, voxels touched, overlap with the design, fixed, load and keep-out regions, whether the region touches the material of final.stl) and the options for its type, and says which option the proposed YAML uses. The agent decides: read the report, change options and call again, edit the YAML, or run it with run_topopt. The tool writes only into the new folder. It refuses an out_dir that is a run folder or inside one, one that holds an input file of the run (the folder of the YAML or of a region STL), a symbolic link, and a folder with files that is not an earlier hints folder; the reply names the fact and the options. After it: check the report, then run_topopt with the proposed YAML and a new out_dir, then compare_runs. Reply keys: resource topopt://replies/marks_to_hints (the meaning of each key).

marks: the path of marks.json (the Refine page exports it: version 1, mm, the frame of final.stl), its JSON text ("Copy JSON" on the page) or the marks object. run_dir: the run the marks belong to. Default: the last run of this server. Needs run.json and the YAML it names. out_dir: the new folder. Default: -hints beside the run folder. It holds the proposed YAML (the YAML of the run, with the changes), the region STLs (the originals are copied, the hints are new) and hints.json (the full report; its paths are relative to the folder). detail: the full report in the reply (about 1.5 KB for each mark). Default: a short reply; hints.json has the full report. options: remove ("keep_out" or "skip"), add ("solid" or "skip"), radius_scale (default 1.0; 0.5 gives smaller regions), protect_regions (default true: fixed and load regions are cut out of a keep-out hint), clip_to_design (default true: a solid hint is cut to the design space), per_mark ({mark id: option}). overwrite: write again into a folder that holds an earlier hints.json. yaml_path: the YAML of the run, when run.json names a file that is not there (a moved run). The labels check in the report says if it fits the run. The input YAML, the run folder and the region STLs of the run stay as they are; the new region STLs touch the grid only inside the box of the input regions. Mapping in this version: remove -> a keep-out STL (sphere, or capsule chain for a stroke) of radius radius_mm x radius_scale; add -> a forced-solid region (a load region that no load case uses); smooth -> facts and options only, because the YAML has no key that smooths one place. mirror repeats the mark at y -> -y. normals, amount_mm, strength and note are not used. The marks are read in file order and the first mark wins an overlap: a later hint region is cut by the earlier ones (a mark inside an earlier one has status no_effect, with the reason).

NameRequiredDescriptionDefault
marksYes
detailNo
optionsNo
out_dirNo
run_dirNo
overwriteNo
yaml_pathNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare a non-idempotent, destructive write operation, and the description adds substantial context beyond that: it writes only into a new folder, refuses specific out_dir locations, copies original region STLs, leaves the input YAML/run/region STLs unchanged, and documents overwrite behavior. It also explains overlap handling, file-order precedence, and which mark fields are ignored.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action and scope, then proceeds through behavior, workflow, reply keys, parameters, and mapping in a logical order. It is long and dense, but most of the length is justified by seven undocumented parameters and complex refusal/default behavior. Some sentences could be tightened, but the structure is appropriate for the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must explain return behavior, and it does: it identifies reply keys via `topopt://replies/marks_to_hints`, describes `detail` versus `hints.json`, and explains that invalid out_dir replies name the offending fact and options. Combined with the parameter semantics and safety constraints, an agent has enough context to call and interpret the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description fully compensates by documenting all seven parameters: accepted forms for `marks`, run resolution for `run_dir`, default and contents of `out_dir`, `detail`, nested `options` keys and defaults, `overwrite`, and fallback behavior for `yaml_path`. This adds essential meaning that the bare schema does not provide.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: it turns Refine-page marks into facts, options, and a proposed YAML in a new folder. It also explicitly scopes the operation as editing no mesh and distinguishes the output folder from the run, which lets an agent separate it from siblings such as apply_marks and run_topopt.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear workflow guidance: after the call, check the report, then run_topopt with the proposed YAML and compare_runs. It also explains the agent can read the report, change `options` and call again, or edit the YAML. It does not explicitly name when to use this instead of `apply_marks` or other mark-related siblings, so it falls short of full when/when-not/alternatives coverage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

printer_materialsList filaments for a printerA
Read-onlyIdempotent

Which filaments can this printer print? Every current filament of the catalog and the user file, grouped by state, with the reasons (older sheets of a listed product are counted in note). It reads; it changes nothing.

printer: a printer as the user says it (a name or id; see find_printer). Without it, the printer of the preferences file (print.printer_model) is used; if there is none, the reply is {"ok": false, "error": ...} that says how to name one. States (facts about the stated values, not a stop; no run is refused because of them): ok (every stated value fits), care (it can work, and the person has to do or know something: fit a hardened nozzle or a chamber heater, take the lower part of a temperature range), no (a stated need is above a stated limit of the printer as it ships, for example an enclosed printer, a nozzle temperature or a bed temperature; the user may have changed the printer), unknown (a value is missing on one side; the reason names it). Returns: ok, printer (id, name, origin, from), catalog_version, counts, groups, available, user_file, note.

  • groups: ok, care, no, unknown, each a list of {id, name, family, origin, available, source, reasons}. reasons lists the checks that are not ok (check, state, text); the text names both values that it compares. source is the data sheet of the filament; the source of the printer is printer.from. The reply is long (about 70 filaments): read the groups that matter and name the few that the user asked for.

  • available: the filaments of filaments.available of the preferences, each with its state; they are also marked in the groups. An id that is not found now is left out and named in not_used; an older sheet has its state and a note with the newer id. Say it as a fact with the reason ("PLA Basic: ok on a P1S", "ABS on an A1 mini: no, the maker asks for an enclosed printer"). The user decides. A filament that is not listed: find_material, then save_material.

NameRequiredDescriptionDefault
printerNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only/idempotent, but the description adds real value beyond them: the error shape {"ok": false, "error": ...} when no printer can be resolved, the fact that no run is refused because of a state, the ~70-item reply size with advice to read only relevant groups, and the not_used / older-sheet handling. Nothing contradicts the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose, then parameter, then state definitions, then return shape — a sensible order. It is dense and long, with heavy backtick notation and parentheticals, but nearly every sentence carries decision-relevant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, yet the description enumerates the return fields (ok, printer, catalog_version, counts, groups, available, user_file, note) and the per-item shape (id, name, family, origin, available, source, reasons). Combined with annotations covering the safety profile and the state taxonomy, an agent has everything needed to call and interpret it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the single parameter is undocumented in the schema, so the description carries the full burden — and it does: accepts a name or id, points to find_printer for naming, and defines the fallback to print.printer_model in the preferences file with the resulting error behavior.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific user question ('Which filaments can this printer print?') and states the resource and scope precisely: every catalog and user-file filament, grouped by state, with reasons. It is clearly distinguishable from catalog-search siblings like find_material, which it explicitly routes to for unlisted filaments.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear usage context and alternatives: use find_material then save_material for a filament that is not listed, and see find_printer for how to name a printer. It also defines the default behavior when the printer argument is omitted. It does not state an explicit 'do not use this when...' case, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ratchet_approveDecide a waiting candidateA
DestructiveIdempotent

The opt-in owner gate: promote the accepted candidate that waits, or drop it.

A ratchet started with stop_before_promote (or acceptance.owner_gate: true) stops before it promotes an accepted candidate. ratchet_status shows it as pending with state waiting_for_owner. The owner decides; this tool writes the decision to the log (owner_approval: given or declined). Ask the user first. It does not start a job: after an approval, call ratchet_run again with the same root to judge the next candidates against the new parent. root: the ratchet folder (default: the last ratchet that this server started). id: the candidate (for example c003). Default: the one that waits. decline: drop the candidate instead of promoting it. Reply: ok, id, owner_approval, promoted (the new parent folder, or null) and parent.

NameRequiredDescriptionDefault
idNo
rootNo
declineNo

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true and idempotentHint=true; the description adds real value on top by explaining what gets destroyed (decline drops the candidate), that the decision is written to the log as owner_approval, and that it does not start a job. The one gap is that it doesn't restate reversibility beyond the drop semantics, but the destructive edge is well covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core decision semantics, then organized into labeled lines for each parameter and the reply. Dense but every line adds information; a small amount of prose could be tightened, but nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, and the description compensates by enumerating the reply fields (ok, id, owner_approval, promoted, parent), including that promoted may be null. Combined with the workflow precondition and follow-up, an agent has everything needed to call and interpret it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden, and it does: root is defined with its default (last ratchet this server started), id is defined with an example format (c003) and its default (the waiting one), and decline is defined as drop-instead-of-promote. All three parameters gain meaning beyond their bare schema types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: the owner gate that promotes or drops the accepted candidate that is waiting. It is immediately distinguishable from ratchet_run and ratchet_status, both of which it references by name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit about the precondition (a ratchet started with stop_before_promote or acceptance.owner_gate), what status shows it as (pending / waiting_for_owner), that the user must be asked first, and the follow-up action (call ratchet_run again with the same root). No inference required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ratchet_runJudge candidate editsA
Destructive

Judge candidate edits of a finished part and keep the ones that pass the rules of the YAML (the ratchet).

The start part is judged first (the baseline). A candidate that passes every listed rule becomes the new parent (folder acc_NN in the ratchet root). A candidate that fails is kept in the log with the reason. The rules are the list acceptance.rules in the problem YAML; a rule that is not listed is off. Nothing in the start run is written. estimate_only: default True. It returns the rules, what each rule needs, what is missing (a rule with a missing input fails every candidate), the number of candidates and the time of verify (its own estimate), and starts nothing. Tell the user the numbers, then call again with estimate_only=false. A real start returns at once (a detached process does the work, like verify_run); call ratchet_status to watch it. Only one job goes at a time on this machine. Reply to a start: ok, started, run_dir, root, pid, log_file, check (the estimate), message. On a wrong input: {"ok": false, "error": ..., "exit_code": 1 or 2}. run_dir: the finished run (needs run.json, labels.bin for marks, result/final.stl). Default: the last run of this server. source: marks:FILE (a marks file of the Refine page: one candidate for each mark, made by apply_marks) or stl:FOLDER (each STL file of the folder is a candidate). marks: a marks file, the same as source="marks:FILE". root: the ratchet folder (default: beside the run folder, <run folder>-ratchet). A second call with the same root goes on where the first stopped. If the rules, the mesh size or the inputs (the YAML, the region files) differ from the ratchet in the root, the call stops with the facts: use a new root; or rebaseline=true (judge the current parent again under the new inputs, keep the log); or overwrite=true (it moves the old files into earlier_NN). override_lock: run although another process holds the job lock of the root. stop_before_promote: the owner gate. The job stops before it promotes an accepted candidate (ratchet_status shows pending); ratchet_approve promotes it or drops it. Off by default; the YAML key acceptance.owner_gate does the same. yaml_path: the problem YAML, if the path in run.json is not valid. max_candidates: judge at most this many in this call. mesh_size_mm: the size of the baseline and of all candidates. Each candidate is judged against the current parent with topopt printcheck and, if a rule needs it, topopt verify at the mesh size of the baseline. Every limit comes from the YAML and the log names its source. A stress or stiffness rule on a marks candidate is judged like on any other candidate. If verify refuses the surface (an apply_marks step that fell back to the plain boolean seam), the log record has errors.verify and the rule check is no_input.

NameRequiredDescriptionDefault
rootNo
marksNo
sourceNo
run_dirNo
overwriteNo
yaml_pathNo
rebaselineNo
mesh_size_mmNo
estimate_onlyNo
override_lockNo
max_candidatesNo
stop_before_promoteNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare a destructive, non-idempotent, non-read-only write, and the description goes well beyond them: the start run writes nothing, a real start returns immediately because a detached process does the work, a second call with the same root resumes rather than restarts, overwrite relocates old files into earlier_NN, and override_lock bypasses a held job lock. It also documents side-effect details annotations cannot express, such as `errors.verify` and `no_input` on refused surfaces.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and default workflow are front-loaded, and each subsequent block maps to real parameters, so little is wasted. However, it is a dense run of unbulleted prose paragraphs, and a scannable list for the dozen parameter semantics would make it easier to extract the right flag under time pressure.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 12-parameter, destructive, long-running job with no output schema and zero schema coverage, the description covers the call ordering, async nature, resume/conflict behavior, promotion output fields, and error shape ({"ok": false, "error": ..., "exit_code": 1 or 2}). An agent has everything needed to invoke it correctly and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% with 12 parameters, so the description must carry the full burden — and it does, defining run_dir requirements, the two `source` forms (`marks:FILE`, `stl:FOLDER`), root defaults and resume semantics, what each of rebaseline/overwrite/override_lock/stop_before_promote/max_candidates/mesh_size_mm does, and the estimate_only default. Almost every parameter gets semantics the schema cannot supply.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names a specific verb and resource — 'judge candidate edits of a finished part and keep the ones that pass' — and immediately defines the mechanism (baseline parent, promotion to acc_NN, failures logged). It is clearly distinguishable from ratchet_status (watching) and ratchet_approve (promoting), which are named later.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly prescribes the default workflow — estimate_only defaults True, 'Tell the user the numbers, then call again with estimate_only=false,' then 'call ratchet_status to watch it' — and names the alternatives for conflicting roots (new root, rebaseline, overwrite). It also states the concurrency constraint ('Only one job goes at a time on this machine'), so the agent knows when a call will block or conflict.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ratchet_statusShow ratchet statusA
Idempotent

Show the state of a ratchet: counts, the current parent, the last records with the reasons, and the job.

root: the ratchet folder (default: the folder of the last ratchet that this server started). last: how many of the last records to show (each: id, decision ACCEPT or REJECT, the rules that failed, the reasons, promoted, owner_approval). The whole log is ratchet.jsonl in the root: one JSON line for each record. States: starting, running (the job process is alive; file_state holds the state of the file when it is a final one that waits for the process to end), finished (every candidate was judged, or max_candidates was reached), waiting_for_owner (the opt-in gate: pending lists the accepted candidates, ratchet_approve decides), baseline_failed (the start part could not be judged), stopped_after_approval (ratchet_approve ended the job after an approval), failed (the last process ended with an error, for example a refused start: last_error has the exit code and the text; or it stopped with no exit code and no final state, for example killed: log_tail has its last output) and none (no ratchet in the folder). The final states show only after the process has ended, so the next call (ratchet_approve or ratchet_run) is not refused as busy. Nothing calls you back when the job ends: call it again in this turn until the state is finished, waiting_for_owner, baseline_failed, stopped_after_approval or failed, or process_alive is false, or end the turn and tell the user what to ask for the result. A promise of a later report cannot be kept. Also: job (the facts of the job: state, exit code, wall time, peak memory), process_alive, pid, mesh_size_mm (one size for the whole ratchet), baseline (its failed rules and facts), log_facts (a skipped partial line).

NameRequiredDescriptionDefault
lastNo
rootNo

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it discloses that final states appear only after the process ends, that the next call is therefore not refused as busy, that nothing calls back at job end so polling in the current turn is mandatory, and that a promise of a later report cannot be kept. It also explains failure diagnostics (last_error exit code, log_tail for killed processes) and the skipped partial line in log_facts. This is a rich behavioral contract that annotations alone could not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose, but the body is one dense block where the state enumeration, polling loop, and return-field list are interleaved, and the trailing 'Also:' sentence lists return fields after the behavioral advice. The content mostly earns its place, but the run-on state definitions and lack of grouping make it harder to scan than it needs to be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description takes full responsibility for return values and does so completely: every state name, the job facts, process_alive, pid, mesh_size_mm, baseline, and log_facts. An agent has everything needed to call it and interpret the result without further documentation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must carry both parameters, and it does: 'root' is defined as the ratchet folder with its default (the folder of the last ratchet this server started), and 'last' is defined as how many trailing records to show, with each record's fields spelled out (id, decision, failed rules, reasons, promoted, owner_approval). It even points to ratchet.jsonl as the underlying log.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Show the state of a ratchet') and immediately enumerates what is shown: counts, current parent, last records with reasons, and the job. This clearly separates it from ratchet_run (which starts a job) and ratchet_approve (which decides), even though neither sibling is named as the explicit contrast.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit operating instructions: 'call it again in this turn until the state is finished, waiting_for_owner, baseline_failed, stopped_after_approval or failed, or process_alive is false', and names ratchet_approve/ratchet_run as the next calls to make. What's missing is a plain statement of when to prefer this over case_status or run_status, but within the ratchet family the routing is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

record_briefRecord the briefA
Destructive

Record the brief of a problem YAML: what the user wants and the assumptions that you state. Say it, then go on.

A case is one problem YAML with the STL files it names, one brief and many runs. This call makes the case (the files <yaml stem>.case.json and <yaml stem>.case-log.jsonl beside the YAML) or replaces its brief. The case keeps the SHA-256 of the YAML and of each region file with the brief, and the values of the method keys of the YAML. If a file or a requirement key changes later, case_status and run_topopt say that the brief is stale and name it. For a case with no brief or a stale brief, run_topopt returns awaiting_user with an override. A change of a method setting (for example settings.solver or settings.voxel_size) is a fact and not stale: run_topopt goes on, and brief_facts names the key with both values, so that you can report it.

yaml_path: the problem YAML in the work folder. A YAML outside the work folder (an example in the code folder, for example) gets no case file: the reply gives the fact and the options. A YAML in the code folder of a source checkout is recorded, with a fact and an option (a work folder is the better place). text: the brief in plain words: the goal, the loads and where they come from, the mounting, the material, the critical sizes. assumptions: a list of {"text": ..., "origin": ...}. origin is user (the user said it), inferred (you concluded it) or default (a default value). The YAML assumptions list is a list of strings that run.json copies; the reply names the texts that differ from the brief. criteria: what the result has to show, in the same form (optional).

NameRequiredDescriptionDefault
textYes
criteriaNo
yaml_pathYes
assumptionsNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With destructiveHint=true already declared, the description still earns its place by naming the two files written (<yaml stem>.case.json and <yaml stem>.case-log.jsonl) beside the YAML, saying the brief is replaced rather than duplicated, and disclosing what is fingerprinted (SHA-256 of YAML and region files, method key values). It goes further to explain staleness propagation to case_status and run_topopt, and the deliberate exception that method-setting changes are facts, not staleness. That is substantial behavior beyond the annotations and no contradiction with them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first sentence and the per-parameter block is well organized. It is on the long side, though: the brief_facts method-key aside and the 'you can report it' tail add words without changing how the agent calls the tool, and one clause ('say that the brief is stale and name it') is slightly clipped.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutating tool with 0% schema coverage, four parameters, no output schema and only hint-level annotations, this covers everything an agent needs: what is written, where, what replaces what, all four parameter meanings, path edge cases, and how the result feeds later checks. Nothing essential is left dangling.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and all four parameters are undocumented in the schema, so the description carries the full load — and does. yaml_path gets its work-folder constraint and edge cases, text gets its expected content (goal, loads, mounting, material, critical sizes), assumptions gets the {text, origin} shape with the three origin values user/inferred/default spelled out, and criteria is noted as optional with 'same form.' That is meaning the schema cannot supply, since its items are just additionalProperties:true objects.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first line gives a specific verb and resource — record the brief of a problem YAML — and scopes it to 'what the user wants and the assumptions that you state.' It then defines the case concept and names the sibling tools that consume the brief (case_status, run_topopt, brief_facts), so an agent can tell exactly where this fits among 30 siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It says when the call creates a case versus replaces a brief, what happens for a YAML outside the work folder (no case file, reply gives facts and options), and what a source-checkout YAML gets. It also states the downstream consequence — run_topopt returns awaiting_user with an override when the brief is missing or stale. What it does not do is tell the agent when to prefer this over a sibling first step (e.g. check_problem or show_problem) before recording.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_partRender a part to imagesA
DestructiveIdempotent

Render a part to PNG images so you can look at it. No display or GL is needed (CONTRACTS.md section 15).

A look before the first run and after each run finds a wrong region or load fast.

Input: stl_paths (STL files; roles: one role for all or one per file, from part, design, fixed, load, keep-out; default part; an item may be a comma list), or run_dir (renders result/final.stl and the region STLs that run.json names; missing region files are listed in the facts), or yaml_path (a problem YAML, before a run: the region STLs and the interface shapes. Fixed, load and union shapes are solid. The design space, keep-out regions and cut shapes are ghosts. A face is its cut zone, clipped to the grid box. Look at it before a run: it shows what a cut takes). With none of them, the last run is used. A YAML render also draws the force arrows (one for each force of each load case, a color for each case, along the force, ending where it acts): you can show it to the user to check the directions before the run. The answer is a JSON text and, when inline is true, the montage as one image. With inline false the answer is the text only; the PNG files are on disk and a client that can open files reads them. A 4-view render of an 85,000-triangle part takes about 2 to 4 s; the first call with an empty numba cache adds under 1 s. Later renders overwrite PNGs with the same names; out_dir picks another folder. out_dir: default /renders, or renders beside the first STL. max_triangles: refuse meshes with more triangles than this (default: no limit; the facts give a memory estimate, about 450 MB plus 450 MB per million triangles). Reply keys: resource topopt://replies/render_part (the meaning of each key). The facts of each mesh have watertight and winding_consistent. loads: false draws no force arrow in a YAML render (default: arrows). A moment and a pressure get no arrow, and the facts say so. The arrow length is a share of the part size: it does not show the force size. views: names from iso, front, back, right, left, top, bottom (default iso, front, right, top); NAME:dx,dy,dz gives your own direction from the part to the camera, z up (name: letters, digits, _, -). section: "x=30" (or "x>=30") keeps x >= 30; "x<=30" keeps x <= 30; the axis is x, y or z, in mm. regions: how the non-part meshes are drawn. ghost (default with a part): design and keep-out as faint ghosts, fixed and load as strong ghosts, so the part stays visible. solid (default without a part). off: the part only. size: one tile in pixels, WxH (default 640x480). The montage is at most 1568 px on the long edge. All tiles have one scale; a scale bar shows it. In views, one item may be "fl:-0.5,-1,0.25". A text like "iso,fl:-0.5,-1,0.25,top" in one item is read as three views. Cut faces are flat orange. With a section and no views, the views are: cut (straight at the cut face from the removed side), iso-cut, and two side views of the kept part. The facts give cut_face_visible_px for each view; they say if a mesh could not be cut (for example, it is not a closed solid), and the render is made anyway.

Colors: part grey-blue, design space light blue, fixed dark blue, load red, keep-out brown, cut face orange; for a YAML also union shape green and cut shape (a ghost) pink-red. Back faces are magenta: they show a flipped or open surface. The same input gives the same PNG bytes.

NameRequiredDescriptionDefault
sizeNo
loadsNo
rolesNo
viewsNo
inlineNo
out_dirNo
regionsNo
run_dirNo
sectionNo
stl_pathsNo
yaml_pathNo
max_trianglesNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructive, idempotent, and non-read-only behavior, and the description explains why: later renders overwrite PNGs with the same names, out_dir redirects output, and same input yields same PNG bytes. It also adds timing, memory estimates, inline-vs-disk output behavior, and facts about mesh validity, going well beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but dense and front-loads purpose and usage before parameter details. Some sentences pack multiple concepts, such as view syntax and section-cut behavior, which slightly hurts readability, but the length is justified by 12 undocumented parameters and complex output behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers input modes, parameter formats, defaults, return shape, PNG overwrite behavior, view and section semantics, color conventions, performance limits, and mesh failure facts. With no output schema and zero schema descriptions, this is complete enough for an agent to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description explains all 12 parameters in prose: stl_paths/run_dir/yaml_path input precedence, roles, views syntax, section syntax, regions modes, size, max_triangles, loads, inline, and out_dir defaults. This fully compensates for the missing schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Render a part to PNG images so you can look at it,' and adds that no display or GL is needed. It distinguishes the tool from run/verify siblings by framing it as visual inspection before and after a run.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit timing guidance: 'A look before the first run and after each run finds a wrong region or load fast,' and notes YAML renders can be shown to the user to check force directions before a run. It does not explicitly name sibling alternatives to use instead for numeric or status checks, so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_historyShow run historyA
Read-onlyIdempotent

Facts of the earlier runs under a folder, newest first, read from the files on disk. Writes nothing.

Use it to see what was tried: state, the YAML of each run, key settings, main metrics. A missing or partial file (no metrics.json, a cut last history line, a broken status.json) is a fact in problems, not an error. CONTRACTS.md section 21.

root: the folder to search (relative paths start at the work folder). Default: the work folder. depth: how many levels of folders to search (default 2: runs/ under the work folder; at most 5). A run folder holds run.json or status.json. A root that is a run folder gives that run. The scan stops after 5000 folders and says so. limit: the newest runs only (default 20). count is the number of runs found, and a note says when older runs are left out. 0 gives all runs. detail: the full facts of each run (all settings, all metrics, which files exist). Each run: name, run_dir, path (relative), state, iteration, iterations, process_alive, modified, yaml_path, yaml_exists, yaml_newer_than_run (the YAML file is newer than the run: it may not be the one that ran), settings (voxel_size_mm, volume_fraction, iterations, solver, filter_radius_mm, n_active, load case names), metrics (compliance_initial and compliance_final, mass_final_g, volume_final_mm3, volume_fraction_final, run_time_s), metrics_source and problems. list_runs is the cheaper list (it reads no metrics).

NameRequiredDescriptionDefault
rootNo
depthNo
limitNo
detailNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, yet the description adds real context beyond them: missing or partial files surface as facts in `problems` rather than errors, the scan caps at 5000 folders and reports it, and `limit` truncation is announced via `count`. It also warns that `yaml_newer_than_run` means the YAML may not be the one that ran.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then structured per-parameter. It is fairly long because there is no output schema and it enumerates every returned field, which earns most of its space, but the field list is dense enough to border on reference-doc dumping.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so documenting the return shape is necessary and the description does it field by field (name, run_dir, state, settings, metrics, metrics_source, problems). Combined with the parameter and edge-case coverage, an agent has everything needed to call and interpret it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden and does: root (relative paths resolve from the work folder, default), depth (default 2, max 5, what makes a folder a run folder, run-folder root shortcut), limit (default 20, 0 means all, count semantics), and detail (what extra is included). This is more than the bare schema types convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('facts of earlier runs under a folder, newest first, read from files on disk') and explicitly differentiates itself from the sibling list_runs ('the cheaper list, it reads no metrics'). The agent can pick between run_history and list_runs without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use it to see what was tried: state, YAML, key settings, main metrics' gives a clear usage context, and the closing sentence names the cheaper alternative list_runs with the tradeoff. It lacks an explicit 'do not use this when...' exclusion, for example versus compare_runs or run_status, so it stops short of the top band.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_resultGet the run resultA
Idempotent

Get the final metrics, the path of final.stl and a text preview when the run is done.

Tell the user the result: mass, stiffness, run time. Units: mm, N, MPa, g. A run that a request to stop ended has no result: the reply is done: false and stopped: true with the pass.

run_dir: the run folder. Default: the last run that this server started. preview: add mesh facts and ASCII silhouettes of final.stl (for clients that cannot open files). render_part gives real images of the part. Reply keys: resource topopt://replies/run_result (the meaning of each key). A note names a wall thinner than the voxel size. The thinnest wall (thinnest_wall_mm) is the lower end of the film, not a value to use. The setting settings.part_only_min_film_mm (the wall thickness to cut off, in mm; default off) cuts off that thin film; then part_only also has min_film_mm, film_removed_mm3 and, for each body, thin_area_mm2, cut_area_mm2, thin_area_after_mm2 and the thinnest wall that stays. To apply it to a run that has finished: write the YAML with the value as a NEW file in the folder of the old YAML (region paths start there), then run_topopt with that YAML, the run folder as out_dir, resume=true and allow_changed_inputs=true (the post step repeats; copy the run folder first to keep the old result). Read the three areas and change the value if the film is still there. For a run with a stress limit, "met" of metrics.stress.cases.<case>.relaxed is the relaxed measure of the optimizer, not the stress of the part. summary and independent_check of the case give the P2 p99.9 of verify_run and its ratio to the limit when verify has run on the folder (read again at each call), else the option to run it.

NameRequiredDescriptionDefault
previewNo
run_dirNo

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Rich disclosure beyond the annotations: stopped runs return `done: false` and `stopped: true`, verify-derived fields are re-read on every call, and reply key meanings live at topopt://replies/run_result. It does not explain why annotations mark this a non-read-only-but-idempotent operation, so the side effect implied by readOnlyHint=false goes unaddressed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Core purpose and units are front-loaded, which is good, but the body drifts into a multi-step recipe for re-running run_topopt with settings.part_only_min_film_mm, which is workflow guidance rather than this tool's contract. The telegraphic run-on phrasing makes the thin-film and stress paragraphs hard to parse on a first read.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the full burden and meets it: shapes for successful and stopped runs, units, the key-documentation resource, thin-wall field semantics, and the distinction between relaxed optimizer stress and verifier P2 p99.9. An agent has enough to interpret the reply correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must carry both parameters, and it largely does: run_dir is the run folder defaulting to the last run this server started, and preview adds mesh facts plus ASCII silhouettes. The run_dir path format (absolute vs relative to the YAML) is still not spelled out.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and a concrete payload: final metrics, path of final.stl, and a text preview, gated on the run being done. It also names the sibling that does something different (render_part for real images) so an agent can separate the two without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear conditions: call when the run is done, preview=true only for clients that cannot open files, render_part for actual images, verify_run for the independent stress check. It never explicitly contrasts with run_status, so the boundary between 'status' and 'result' is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_statusShow run statusA
Read-onlyIdempotent

Show the state of a run: status, last iteration, and a one-line summary.

Call it again to watch a run. Each call returns at once. Nothing calls you back when the run ends: call it again in this turn until the state is done, error or stopped, or process_alive is false, or end the turn and tell the user what to ask for the result. A promise of a later report cannot be kept. The numbers are facts; you decide what to do next. run_dir: the run folder. Default: the last run that this server started. job has the facts of the run process: state (running, done, stopped, failed with its exit code, or stale_lock when the process stopped without a marker), wall time and peak memory. history_facts names lines that were skipped. state is stopped for a run that a request to stop (stop_run, topopt stop) ended at the end of a pass: the checkpoint is saved, there is no result/, and run_topopt with resume=true continues it. A process of this server can still be alive after that: it only serves the dashboard (process_alive true, job.state stopped). stop_request is the request in the run folder (null if none): while the job is running it means the run stops at the end of its current pass. checkpoint (null if the folder has none, or the state is starting, error before any data, or none) gives the pass of the last checkpoint, complete (the run reached its last pass or a stop rule) and yaml_path: run_topopt with resume=true continues a run that stopped before its last pass. verdict (null until the run ends) has the state (converged, iteration_limit, stopped_by_rule, stopped_by_request, unfinished), whether the constraint rows are met (feasible), the measures with their thresholds, the stop rule that fired, and the resume points. The same verdict is in metrics.json (run_result). verdict.facts has the facts of the last pass, and the verdict text ends with "Facts: ..." for each fact that the run has: the volume used (the projected design, and the thresholded part at density 0.5; only with a volume row); the load path (which load regions the thresholded part does not join to a fixed, spring or joint region; in the text only when a region is not joined); for a run with objective mass, the material (volume and mass of the thresholded part; only with no volume row) and, when the grayness is above grayness_max, the grey design (volume and body count of the thresholded part at the cuts 0.4, 0.5 and 0.6, and the volume spread between 0.4 and 0.6 as a share of the volume at 0.5). They are facts: no test uses them. The run log has them at the end of each beta stage. The body count of final.stl comes after the post step: metrics.grey_design (see run_result). A run that ended with no result also has log_tail, failure (facts: pid, exit code, signal, run data, whether this server stopped it, peak memory, estimate, RAM), options and, after a signal or an unseen end with no message, possible_causes (not a verdict). fine_run (the first folder of run_topopt with fine_pass=true): the folder and the state of the fine pass. time_left (while the run is in its passes, from pass 2 of the run process) has left_s and up_to_s (seconds left if no stop rule or request to stop ends the run earlier) and basis. Else it is null, with the reason in time_left_note.

NameRequiredDescriptionDefault
run_dirNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish read-only, idempotent, non-destructive behavior, and the description adds substantial context beyond them: immediate return, no callback, process_alive semantics, stale_lock, stopped-state behavior, checkpoint continuation, verdict availability, and failure/log_tail details. It does not contradict any annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose and polling guidance, then moves into field-level return semantics. It is unusually long and dense, but because there is no output schema, most of the detail about state, checkpoint, verdict, and failure fields earns its place. Slightly better chunking or bullet structure would improve readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex status tool with no output schema, the description is complete enough: it covers polling behavior, state meanings, checkpoint/verdict fields, failure details, fine_run, and time_left. Given the single optional parameter and rich read-only annotations, an agent has what it needs to call and interpret the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage for the single run_dir parameter, so the description must compensate. It explains that run_dir is the run folder and gives its default as the last run started by this server, which is the key semantic an agent needs for an optional path parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb and resource: showing the state of a run, including status, last iteration, and summary. It also distinguishes the tool from siblings by naming stop_run, run_topopt, and run_result in context. An agent can tell this is the monitoring/status tool rather than the result or stop tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says to call it again to watch a run, that each call returns immediately, and exactly when to stop polling: done, error, stopped, or process_alive false. It also warns that nothing calls the agent back and says to end the turn and tell the user what to ask for the result. It names stop_run and run_topopt resume as related actions, giving clear alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_topoptStart an optimization runA
Destructive

Start a topology optimization run in the background. Returns at once.

Use after check_problem and after you state your assumptions to the user. If the user gave no load (no object, no mass and no force), ask first. Then run_status to watch it, and run_result when it is done. Nothing calls you back when the run ends: call run_status in this turn, or end the turn and tell the user what to ask. It also returns assumptions (the strings of the YAML) and derived (forces in N, voxel size, minimum feature size, volume fraction), so you can show them. Reply keys: resource topopt://replies/run_topopt (the meaning of each key, and the fine pass: fine_from, fine_pass).

yaml_path: the problem YAML (relative paths start at the work folder; environment shows it). out_dir: the run folder. Default: runs/live in the work folder (the dashboard shows it). Without resume, a folder that holds the checkpoint of a run that did not finish loses it: the reply then has earlier_checkpoint (the pass and a note), and the run goes on. override_lock: a live process can hold the job lock of the run folder (the reply names its pid and start time). Give true to run anyway. A lock of a stopped process is replaced without it. proceed_without_brief: a YAML with a case file (made by record_brief) can have no brief, or a stale brief (a changed STL file or requirement key). Then the reply is {"state": "awaiting_user", "facts", "options", "override"} and nothing starts. Give true to run anyway: the case log records it. resume: continue the run of out_dir from its last checkpoint (run_status shows checkpoint). The history and the snapshots after it are dropped. The YAML and the region files are read again: if they or the settings changed, the reply is an error with the changes in resume.facts, and nothing is written. A run that stop_run stopped is continued the same way, with no allow_changed_inputs. continue_from: add passes to a run in a NEW run folder (out_dir); this folder is the parent and is only read. more_iterations (with continue_from): the number of passes to add (a whole number of 1 or more, no upper limit). The new run starts from the last checkpoint of the parent (pass K) and has K + more_iterations passes (settings.iterations is not used). The reply has continue. The card run_topopt:continue_from has the rest. allow_changed_inputs: with resume or continue_from, go on with the changed inputs. The run log and the verdict name the changes. With resume=true the stop of proceed_without_brief names both overrides in one option (this one and allow_changed_inputs=true). On a finished run a resume runs the post step only: a key that only it reads (for example settings.mesh_method) takes effect in seconds; a key of the passes is accepted, the part stays, and the reply has resume (with pass_keys). stop_rules: true turns the stop rules on, false turns them off. None: as settings.stop_rules of the YAML says (off by default). A rule ends the run at a pass that only measures. The verdict names the rule and its numbers. With resume, a run that was killed gives the same result as one that was not (bit-equal with one thread and a direct solver). The lost force is in check_problem (before) and in run_result or run.json (after). A moment, a remote force, a pressure or a per-axis support gives extended in check_problem; the stiffness of such a case is null with a reason.

Who decides a change of the YAML: a method setting (penal, beta schedule, solver, voxel size, iterations, a voxel guard: the memory estimate against the RAM first, above it the machine can freeze) you change without asking, and report what, why and the price. A user requirement (loads, supports, keep-outs, material, stress limits and safety factors, a mass target, print limits, symmetry) you may tighten without asking, with a report and its measured price; you loosen it only with the user's consent, and you bring the facts. A key that can be either follows its origin in record_brief. Cards: topopt://levers.

NameRequiredDescriptionDefault
resumeNo
out_dirNo
fine_tolNo
fine_fromNo
fine_passNo
yaml_pathYes
fine_voxelNo
stop_rulesNo
fine_passesNo
continue_fromNo
override_lockNo
more_iterationsNo
allow_changed_inputsNo
proceed_without_briefNo

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations say destructive and non-idempotent; the description earns that with concrete consequences: without resume, a folder holding a checkpoint of an unfinished run loses it, a live lock names pid and start time, resume drops history and snapshots, changed inputs yield an error and nothing is written, and stop_run runs continue without allow_changed_inputs. It also discloses the no-callback model ("Nothing calls you back when the run ends") and that a killed run resumes bit-equal, which no annotation conveys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Strongly front-loaded: purpose and the no-callback constraint come first, then per-parameter notes, then the YAML-change policy. It is long and dense with parenthetical asides, and a couple of sentences (the bit-equal resume claim, where the lost force is reported) are marginal. Nearly every other sentence carries operational weight, so the length is largely justified.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 14-parameter, destructive, long-running background job with no output schema and no schema descriptions, the description still covers start conditions, reply contents (assumptions, derived, earlier_checkpoint, continue, resume.facts), failure modes (lock, missing/stale brief, changed inputs), and restart semantics. It points to named resources (topopt://replies/run_topopt, topopt://levers) for lookup detail.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema coverage across 14 params, the description carries the burden and does so for most of them: yaml_path (relative to work folder), out_dir (default runs/live, checkpoint-loss caveat), override_lock, proceed_without_brief, resume, continue_from, more_iterations, allow_changed_inputs, stop_rules. The five fine-pass params are only named and deferred to the topopt://replies/run_topopt resource, so fine_tol, fine_voxel and fine_passes still lack meaning here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Start a topology optimization run") plus the execution model ("in the background. Returns at once"), which is the fact an agent most needs. It also distinguishes itself from the siblings it hands off to (run_status to watch, run_result when done), so it is not confusable with list_runs, run_status or run_result.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit preconditions ("Use after check_problem and after you state your assumptions to the user. If the user gave no load ... ask first") and explicit follow-up routing (run_status, run_result). It also gives when-to-use rules for the tricky modes: resume vs continue_from ("add passes to a run in a NEW run folder"), override_lock, proceed_without_brief, and allow_changed_inputs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

save_materialSave a filament profileA
DestructiveIdempotent

Keep a filament that is not in the catalog, with its facts and their sources, in topopt-filaments.yaml in the work folder. It writes only that file.

Use it after find_material says "none": look up the data sheet of the maker (web search), show the user the values with the page address, and call this tool after the user agrees. A value that you cannot find stays null (unknown): ask the user for it, and leave it null if they do not know; a guess would look like a fact. The server reads the file at each call, so the filament is live at once. profile: one filament as a dict. Needed: id (lower-case slug, for example "acme-pla-plus"), maker, product, family (PLA, PETG, ABS, PA6-CF, ...), and a source: source_url (the data sheet) or source "user" (the user said the values). A run needs a modulus (the tensile E_xy_mpa or E_z_mpa, MPa; a sheet that gives only a bending modulus gives bending_modulus_xy_mpa or bending_modulus_z_mpa, and E is taken from it) and a density (density_g_cm3, g/cm3) from it, or from the YAML. Optional (null or left out = unknown): aliases (list), sheet_version, E_xy_mpa, E_z_mpa, bending_modulus_xy_mpa, bending_modulus_z_mpa, strength_xy_mpa, strength_z_mpa, strength_kind ("yield", "peak", "not stated"), elongation_xy_pct, density_range_g_cm3 ([min, max] of a sheet that gives a range, with density_g_cm3 null), hdt_18_c, hdt_045_c, nu, nozzle_c ([min, max] in C), bed_c ([min, max]), enclosure ("no", "recommended", "required"), chamber_c_min, hardened_nozzle (true or false), drying (text), direct_drive (true), abrasive (true for fibre), soft (true for TPU), conditioned (wet values of a polyamide: condition, strength_xy_mpa, strength_z_mpa, E_xy_mpa, E_z_mpa), opened (YYYY-MM-DD, the day the page was read), tag ("maker TDS", "maker page", "third party", "user"), field_sources ({field: page address or "user"}), enclosed_note (what the sheet says about printing in an enclosed printer), note. The entry is checked like the shipped catalog. The same id replaces a user entry; the id of a shipped filament is refused with another id to use, and a name or alias of a shipped filament with another product name or alias. Other entries stay. Returns: ok, path, profile, created, replaced, note, problems (of the rest of the file). A wrong argument name or value gives {"ok": false, "error": ...}; nothing is written. A file that is not valid YAML is not changed. There is no CLI command: edit the file.

NameRequiredDescriptionDefault
profileYes

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the annotations: it discloses that only that file is written, that the file is re-read on each call so entries are live immediately, that the same id replaces a user entry while shipped ids/aliases are refused with a suggested alternative, and that other entries are untouched. It also specifies the success payload (ok, path, profile, created, replaced, note, problems) and the error contract (`{"ok": false, ...}` writes nothing, invalid YAML is left unchanged) — consistent with destructiveHint=true and idempotentHint=true rather than contradicting them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, usage ordering, and the unknown-value policy before the field specification, and almost every sentence earns its place given the empty schema. The optional-field enumeration is a dense run-on list, which hurts scanability but is unavoidable without machine-readable property descriptions.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a write tool with a single untyped nested object, no output schema, and annotations that only flag destructiveness, the description supplies everything needed: trigger, user-consent step, full field contract, source-provenance rules, validation behavior, replacement/refusal semantics, and return shape. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single `profile` parameter is a free-form object with no property documentation, so the description carries the entire burden — and does: required keys (id slug format with example, maker, product, family, source_url or source "user"), run-required quantities (modulus via E_xy/E_z or bending modulus, density in g/cm3), and an enumerated optional set with units, ranges, enums, and semantics for every field.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening states a specific verb, resource, and destination: keep a filament absent from the catalog, with facts and sources, in `topopt-filaments.yaml` in the work folder, and scope-limits it to that one file. It is clearly distinguishable from the sibling `find_material` (which is the lookup it follows) and from `save_printer`/`save_preferences`.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit trigger and precondition: "Use it after `find_material` says 'none'", plus a prescribed procedure (look up the maker's data sheet, show values with the page address, call after the user agrees). It also names the alternative path for unknown values and the refusal cases (shipped id / shipped alias) with the required remedy.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

save_preferencesSave user preferencesA
DestructiveIdempotent

Keep the answers of the user (print bed, material, filaments, quality, outputs) for the next runs, in topopt-preferences.yaml in the work folder. It writes only that file.

Use it once, after the user answered. environment shows the file in preferences. The server reads the file at each call. A preference does not change a run by itself: run_topopt and check_problem fill nothing. build_regions takes a material, print or settings.voxel_size that the spec does not have at all, writes it into the YAML and says so in preferences_facts; a block that the spec gives, also a part of one, stays as it is. check_problem names a difference in preferences_facts. Sections (each optional; checked like the problem YAML):

  • print: printer_model (a name or id from find_printer; it gives the bed and type unless the YAML does), printer_type (fdm, sla, lpbf, sls), bed_mm (one number or [x, y] in mm), build_direction (+x to -z, or 3 numbers), self_supporting_angle_deg. A print limit (min_wall_mm) belongs to one part: it is refused.

  • material: E (MPa), nu, density (g/cm3), filament (from find_material; gives E and density), name (free text, for example "PETG").

  • filaments: available (names or ids of the filaments the user has).

  • quality: voxel_size (mm).

  • outputs: renders (render_part), step (export_step), verify (verify_run). The STL and the part card are made in every run. [] is none of the three. A section you do not give stays; one you give is merged key by key: a key with null is removed, and {} removes the section (outputs too). An unknown key stays in the file. With no section it makes an empty file if none exists (the user kept the defaults). Returns: ok, path, values, changed, created, kept_not_used, problems, note. A wrong name, key or value gives {"ok": false, "error": ...} with the key, the value and the rule; nothing is written. It refuses a file that is not valid YAML and a folder that cannot be written. There is no CLI command: edit the file.

NameRequiredDescriptionDefault
printNo
outputsNo
qualityNo
materialNo
filamentsNo

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial behavior beyond the annotations: key-by-key merge semantics, null removes a key, {} removes a section (outputs too), unknown keys persist, and calling with no section creates an empty file. It also discloses error behavior (wrong name/key/value returns ok:false and writes nothing; invalid YAML or unwritable folder is refused) and the return field list, which is consistent with destructiveHint=true.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and the write-scope warning are front-loaded, and the length is justified by 0% schema coverage and five sections. Some lines are heavily telegraphic ('`run_topopt` and `check_problem` fill nothing'), which costs clarity at the margins.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers inputs, merge/removal semantics, error cases, refusals and the return keys for a tool with no output schema and no parameter documentation. Minor gap: return fields such as kept_not_used and note are listed but not explained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and every parameter is an untyped additionalProperties object, so the description carries the entire burden and does: it enumerates print (printer_model, printer_type, bed_mm, build_direction, self_supporting_angle_deg), material (E, nu, density, filament, name), filaments.available, quality.voxel_size, and outputs.renders/step/verify, including units and the rule that min_wall_mm is refused in print.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: it keeps the user's answers (print bed, material, filaments, quality, outputs) in `topopt-preferences.yaml` in the work folder, and pins the scope with 'It writes only that file.' An agent can distinguish it from mutating siblings like save_printer/save_material by the fact that it persists per-user run defaults, though it never names those siblings explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear timing ('Use it once, after the user answered') and a strong non-obvious caveat: a preference does not change a run by itself, since run_topopt/check_problem fill nothing and build_regions only takes a value the spec lacks. It also directs the agent to `environment` to inspect the file and notes there is no CLI equivalent. It stops short of explicitly naming the alternative save tools, so not a full 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

save_printerSave a printer profileA
DestructiveIdempotent

Keep a printer that is not in the catalog, with its facts and their sources, in topopt-printers.yaml in the work folder. It writes only that file.

Use it after find_printer says "none": look up the maker page (web search), show the user the values with the page address, and call this tool after the user agrees. A value that you cannot find stays null (unknown): ask the user for it, and leave it null if they do not know; a guess would look like a fact. The server reads the file at each call, so the printer is live at once. profile: one printer as a dict. Needed: id (lower-case slug, for example "voron-trident"), vendor, model, printer_type ("fdm", "sla", "lpbf", "sls"), bed_mm ([x, y] in mm), and a source: source_url (the maker page) or source "user" (the user said the values). Optional (null or left out = unknown): aliases (list), build_height_mm, nozzle_mm, nozzle_options_mm (list), max_nozzle_c, max_bed_c, enclosure ("open", "enclosed", "heated"), chamber_max_c (only with "heated"), stock_nozzle_material ("brass", "stainless", "hardened_steel", "tungsten_carbide"), extruder ("direct", "bowden"), opened (YYYY-MM-DD, the day the page was read), tag ("maker doc", "third party", "user"), field_sources ({field: page address or "user"}), note. The entry is checked like the shipped catalog. The same id replaces a user entry; the id of a shipped printer is refused with another id to use, and a name or alias of a shipped printer with another model name or alias. Other entries stay. Returns: ok, path, profile, created, replaced, note, problems (of the rest of the file). A wrong argument name or value gives {"ok": false, "error": ...}; nothing is written. A file that is not valid YAML is not changed. There is no CLI command: edit the file.

NameRequiredDescriptionDefault
profileYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations flag the write and its destructiveness but say nothing about blast radius; the description supplies that (only `topopt-printers.yaml` is touched, other entries stay). It also discloses idempotent replacement ('the same id replaces a user entry'), refusal rules for shipped ids/aliases, validation against the shipped-catalog rules, and the no-write failure mode — all consistent with destructiveHint=true and idempotentHint=true.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and write target, then usage sequence, then field spec, then return/error behavior — a sensible order. It is dense and long for a one-parameter tool, but the length is mostly justified by the undocumented profile schema; a few lines (e.g. 'There is no CLI command: edit the file.') are instructional plumbing rather than tool behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given one nested free-form object, no output schema, and mutation semantics, the description covers everything an agent needs: preconditions, per-field validation, collision/refusal behavior, the returned fields (ok, path, profile, created, replaced, note, problems), and the two failure modes (bad argument, invalid YAML) with the guarantee that nothing is written.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the single `profile` parameter is a free-form object with no documented properties, so the description carries the entire burden — and does: required keys with formats (id slug, printer_type enum, bed_mm as [x,y], source_url or 'user'), the full optional set with value constraints ('heated'-only chamber_max_c, nozzle material enum), and null-means-unknown semantics plus field_sources.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: keep a printer that is not in the catalog, into `topopt-printers.yaml` in the work folder. It also scopes itself ('It writes only that file') and implicitly separates itself from `find_printer` (the lookup it follows) and `save_material` (a different file).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit trigger and sequence: use it after `find_printer` says 'none', look up the maker page, show the user the values with the page address, and call only after the user agrees. It also states the negative rule for missing values (stay null, ask, do not guess).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

show_problemShow the problem in 3DA
Read-onlyIdempotent

Show a problem YAML to the user as a 3D view in the chat: the design space, the fixed, keep-out, solid and load regions, an arrow for each load case, and the time and memory estimate. No optimizer run: the same checks as check_problem, in the same time.

yaml_path: the problem YAML (relative paths start at the work folder). A client that shows MCP Apps (for example Claude Desktop) shows the card. The user can turn and zoom it. The view's button "Start the run" works in one of three ways. The host lets the view call tools: the click starts the run at once (run_topopt), the view watches it (run_status), and the host may tell you about the start and the end. While that run works, a second run_topopt is refused; run_status shows the run. When the run folder (runs/live) holds a run, the first click shows what the start replaces; a second click starts. The host takes only a message from the view: the button sends a chat message from the user that asks you to start the run. Neither: the view shows a line for the user to type. Another client shows only the text: the region counts and the estimate. Use it when the YAML is ready, so that the user sees the setup before the run. The full facts and the warnings are in check_problem. On a wrong input: {"ok": false, "error": ...}.

NameRequiredDescriptionDefault
yaml_pathYes

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnly/idempotent/non-destructive, and the description still adds substantial context beyond them: that no optimizer runs, that behavior depends on the client (MCP Apps card vs. text-only fallback with just region counts and estimate), the interaction contract for the 'Start the run' button, and the concrete error shape {"ok": false, "error": ...}.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The opening and closing sentences are front-loaded and efficient, and the key constraint (no optimizer run) lands early. However, the middle block describing the three host modes for the 'Start the run' button is long, chatty, and largely about UI plumbing rather than helping an agent decide to call the tool or how to invoke it.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must cover returns; it does by describing the card contents, the text-only fallback (region counts and estimate), and the error object. It omits whether the card is returned as part of the tool result payload versus rendered side-effect only, which is a minor gap for an interactive-render tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With schema description coverage at 0%, the description carries the burden and does so: it names yaml_path and clarifies that 'the problem YAML' is expected and that 'relative paths start at the work folder', which the bare string schema does not convey. It does not specify the file extension or an example path, which keeps it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb and resource ('Show a problem YAML ... as a 3D view in the chat') and enumerates exactly what the view contains: design space, fixed/keep-out/solid/load regions, load-case arrows, and time/memory estimate. It explicitly distinguishes itself from check_problem ('the same checks as check_problem, in the same time') and from run_topopt ('No optimizer run').

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use it when the YAML is ready, so that the user sees the setup before the run' gives a clear trigger condition. It also routes the agent to the sibling alternative for the full facts and warnings ('The full facts and the warnings are in check_problem'). No explicit when-not-to-use case is stated, keeping it below a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

stop_runAsk a run to stopA
DestructiveIdempotent

Ask a running run to stop at the end of its current pass. Returns at once; sends no signal; waits for nothing.

The tool writes the file job.stop in the run folder. The run then ends with exit code 5. There is no post step and no result/. The history, the snapshots and the checkpoint are those of a run that goes on, so run_topopt with resume=true (no allow_changed_inputs) gives the same result as a run that was not stopped. run_dir: the run folder. Default: the run that this server started and that still works; else the one run in the work folder (or its runs/ folder) that a live process holds the job lock of (this finds a run that the CLI started). If several runs are live, the reply lists them and writes nothing: give run_dir. The reply has state: stop_requested: the request is written. pid, iteration (the pass at the last status), message, options. already_requested: a request is in the folder already (stop_request has its time); it is not written again. postprocess: the run is in the post step or the refine step: all passes are done, nothing is written. Options: wait, or end the process yourself (resume=true then repeats the post step only). nothing_to_stop: the run is done, stopped or failed already: nothing is written. process_alive says whether a process of this server is alive and only serves the dashboard. options has the resume route where a checkpoint is there. gone: a lock whose process is not running, or a record that says running and has no lock: nothing is written. checkpoint and the option resume=true (it replaces the stale lock, with a fact). Also the run process of this server that ended before it took the job lock: the message has its exit and the log file. none: no run in this folder: no job files and no live process, or the folder does not exist, or a live job lock of a job that is not a topopt run (the message names the marker, for example ratchet.json). Nothing is written. several: several live runs: the list is in runs. Every reply has note: a topopt build from before this change does not read job.stop, and a run of such a build ignores the request. found_by says how the run was found (run_dir, this server, the lock scan). The run reads job.stop after the checkpoint of each pass (one file read per pass, no polling). It then saves its verdict (state stopped_by_request), writes the status stopped and the job marker job.STOPPED, and releases the job lock. A pass that is long (a big grid, a buckling row) delays the stop by up to one pass. A solve that hangs never reads the request: the reply has the pid. With run_topopt fine_pass=true and no run_dir, the fine pass is stopped when it runs; while the first run works, that run is stopped and the fine pass does not start. From the post step of the first run until the fine pass has started, the request is written in the fine folder (state stop_requested, run_dir the fine folder): the process reads it before the fine pass starts, ends without starting it (exit code 5) and says so in the log. Only run folders count for run_dir: a folder with status.json or run.json, as in list_runs. The folder of a ratchet job holds a job lock too, and it is not a run.

NameRequiredDescriptionDefault
run_dirNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true, readOnlyHint=false, and idempotentHint=true; the description is fully consistent with those traits and adds extensive operational detail. It discloses the job.stop file mechanism, exit code 5, absence of post step and result/, checkpoint/snapshot preservation, idempotent already_requested handling, stale-lock behavior, and the fact that a long or hung pass may delay or never observe the request.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the key behavior, then organized around run_dir, reply states, and special cases. It is necessarily long because the tool exposes many state-machine outcomes, but it is dense and some passages could be tightened. Still, most sentences carry operational information rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, yet the description documents reply states such as stop_requested, already_requested, postprocess, nothing_to_stop, gone, none, and several, plus note, found_by, pid, iteration, and options. Given the complex edge cases, the description provides enough context for an agent to call the tool and interpret results correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage for run_dir is 0%, so the description must compensate, and it does. It explains the default resolution logic, live-lock scanning, multiple-live-run behavior, fine-pass folder handling, and the restriction that only run folders with status.json or run.json count. This is substantially more than the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb and resource: ask a running run to stop at the end of its current pass. It immediately distinguishes its behavior from alternatives by saying it returns at once, sends no signal, and waits for nothing. The purpose is unambiguous without needing the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit usage conditions for default run discovery, multiple live runs, post-process states, already-completed runs, stale locks, and fine-pass interleaving. It tells the caller when to pass run_dir and what happens if several runs are live. It also names resume=true as the route for inspectable finished/post-process runs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

team_guideGet a role guideA
Read-onlyIdempotent

Playbooks for the roles of a topopt team: lead-design, cad, fea, print and finish.

A role is a job, not a separate agent. One agent can do all five in one conversation. A client that runs sub-agents can give each role to one. A playbook says what the role does, which tools it can use today, what does not exist yet, and what to report. The text is the same as the MCP prompt of that role and the resource topopt://roles/.

role: a role id (lead-design, cad, fea, print, finish). Also accepted: any case, the plugin agent name (cad-engineer) and the resource URI (topopt://roles/cad). Without a role, or with a name that matches none, the answer is the list of roles with one line each. That is a fact, not an error.

NameRequiredDescriptionDefault
roleNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/idempotent annotations, the description discloses the important edge case: an unmatched or missing role returns the role list rather than an error, and it explicitly calls that 'a fact, not an error'. It also states the text is identical to the MCP prompt and the topopt://roles/<id> resource, which prevents an agent from double-fetching.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first sentence, and the alias/fallback details are valuable. The middle paragraph about clients running sub-agents is contextually interesting but marginal filler for an agent trying to call the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a single optional parameter and no output schema, everything an agent needs is present: what the tool returns, what a playbook contains, how aliases resolve, and what happens on a miss. Nothing material is left to inference.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the only parameter, role, is fully explained: accepted values, case-insensitivity, agent-name aliases (cad-engineer), resource-URI form (topopt://roles/cad), and the null default behavior. This is exactly the compensation the low coverage requires.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states it returns role playbooks for the five topopt team roles and enumerates them explicitly, so the resource is unambiguous. The verb is implicit ('Playbooks for...') rather than a direct 'get/return', but it is still far from tautological and is clearly distinguishable from every sibling tool listed.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains the role-vs-agent model and clarifies that one agent can play all five roles, which is real usage context. It also spells out the discovery path when no role is supplied. What it lacks is an explicit statement of when in a workflow an agent should call this versus jumping straight to other tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

verify_runVerify stress of a runA
Destructive

Check the final STL of a finished run with quadratic tets (P2): von Mises stress per load case.

It is independent of the voxel optimizer: it meshes result/final.stl (part_only.stl with part_only) with tets (gmsh), clamps each fixed region (a joint or spring holds the part too), loads each load region with a traction (uniform per area, the resultant is the YAML force), and solves each load case alone (no case weights). Units: mm, N, MPa.

estimate_only: default True. It returns the estimates for each mesh size (memory in bytes, time in s per measured solver), the solver that would run, the extras and the RAM, and meshes nothing. Tell the user the numbers, then call again with estimate_only=false. A real run starts in the background and returns at once; verify_status shows it and gives the result. One verify job or optimizer run at a time: a second start is refused. allowable_mpa, percentile: your allowable stress, no default (ranges: topopt://materials/reference). It adds a limit block. exit_code is 3 if the percentile value (by volume, default 99.9) of a case is above it. With gate it replaces the YAML stress limits (a larger value loosens them: the user's consent). run_dir: the run folder (default: the last run that this server started). It needs run.json and result/final.stl. gate: true adds the key gate (met per check and case; exit_code 3 if it fails); limits: the YAML's, see topopt://levers/verify_run:gate max_gb: refuse above this memory estimate in GB; it also refuses above the available RAM. force: run anyway. On a wrong input or a run that cannot go on: {"ok": false, "error": ..., "exit_code": 1 or 2, "facts": ...} (exit_code 1: bad input, an unsolvable part, no usable solver; exit_code 2: a missing gmsh or scikit-fem, a meshing failure, a memory refusal, an empty region). p99.9 is the main number; the peak can move with the mesh at sharp features. A load patch can hold a large part of the top volume: read near_regions and load_band_sensitivity. mesh_size_mm: one mesh size. Default: the tet mesher size, about 1.3 to 2.2 voxels for an sdf STL. levels_mm: several sizes; the finest is the reference level; the result gets a levels block. region_band_mm: a mesh node belongs to a region when it is inside the region STL or within this band of its surface. Default: 0.5 voxel (counts_by_band: the counts at 0, 0.5 and 1 band). solver: auto (default: cholesky on macOS arm64, pardiso, cholespy, superlu) or a factor name. The result names the one that ran and those auto passed. yaml_path: the problem YAML, if the one that run.json names is gone (moved folder). near_region_mm: distance from a fixed or load region for the stress numbers without the region patches. load_sensitivity: also solve the load at bands of 0 and 2 times the band. part_only: mesh result/part_only.stl (the run needs regions.not_printed); a removed body becomes a boundary condition at its contact face, see topopt://levers/verify_run:part_only. Key: part_only.

Result keys (verify_status, when done): ok, exit_code (0 done, 3 limit failed), cases..von_mises.p99_9_by_volume_MPa. All other keys, and the keys that YAML blocks add (buckling.check, limits rows, bore_checks): topopt://levers/verify_run

NameRequiredDescriptionDefault
gateNo
forceNo
max_gbNo
solverNo
run_dirNo
levels_mmNo
part_onlyNo
yaml_pathNo
percentileNo
mesh_size_mmNo
allowable_mpaNo
estimate_onlyNo
near_region_mmNo
region_band_mmNo
load_sensitivityNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: discloses background execution returning immediately, exit-code semantics (0/3 done-or-limit, 1 bad input/no solver, 2 missing gmsh/meshing failure/memory refusal), a structured error envelope with a facts field, memory refusal via max_gb and force override, and that estimate_only meshes nothing. This is exactly the mutation/concurrency/resource context annotations alone cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and the estimate-only workflow, and each block maps to a parameter or result concern, so little is wasted. It is however dense and telegraphic in places ('With gate it replaces the YAML stress limits'), which costs a little readability for an otherwise well-organized text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 15-parameter, no-output-schema, destructive-capable tool, the description supplies error shapes, result keys, exit codes, resource references (topopt://levers/verify_run) and caveats about p99.9 vs peak. No output schema exists, and the description compensates by naming the return keys the agent must read.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% across 15 parameters, so the description carries the full burden — and it does, explaining estimate_only, allowable_mpa/percentile semantics and the limit block, run_dir defaults, gate vs YAML limits, max_gb/force interaction, mesh_size_mm defaults, levels_mm reference level, region_band_mm membership rule, solver auto-passing, yaml_path fallback, near_region_mm, load_sensitivity bands and part_only's boundary-condition effect.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (von Mises stress per load case on the final STL with quadratic tets) and explicitly distinguishes itself from the optimizer path ('independent of the voxel optimizer'). An agent can tell this apart from run_topopt and run_result without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit two-step workflow (call with estimate_only=true, report numbers, re-call with false), names verify_status as the follow-up for results, and states the exclusion 'one verify job or optimizer run at a time: a second start is refused'. Defaults for run_dir and prerequisites (run.json, result/final.stl) are also spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

verify_statusShow verify statusA
Idempotent

Show the state of a verify job and, when it is done, its result (the content of verify.json).

run_dir: the run folder (default: the folder of the last verify job of this server, else the last run). Call it again to watch the job. Nothing calls you back when the job ends: call it again in this turn until the state is done, error or failed, or end the turn and tell the user what to ask for the result. A promise of a later report cannot be kept. States: starting, meshing, solving, writing (the job works), done, error, failed (the process ended with no final status; log_tail has its last output) and none (no job and no result in the folder). It has elapsed_s and estimated_seconds_total (the estimate of verify_run). result: with a done job, add the result (set false to get the state only). result_matches_final_stl says whether the result is for the mesh file that the folder has now (result.run.verified_file: nominal.stl when the run has machining stock, else final.stl; part_only.stl after verify_run with part_only=true, and then the result has the block part_only). If it is false, the result belongs to an older file: run verify_run again. Tell the user the numbers; you decide what to do. plain (a done job with the result): one plain line for each load case (the value that is compared, who gave the allowable, the margin) and a line for what the check does not cover. They are a base for the answer to "will it break?". partial, coverage (a done job; also with result=false): partial is true when a check that the YAML or the call asks for failed or did not run; the other numbers still stand. coverage has ran (names), failed (name, reason) and not_run (name, reason, asked). A check that was not asked for is under not_run with asked false and does not make the result partial. Then summary and the first plain line say so.

NameRequiredDescriptionDefault
resultNo
run_dirNo

TDQS

A4.1/5.0
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations declare readOnlyHint=false, but the description frames the tool purely as a status/result viewer that shows state and returns verify.json content. That is an annotation contradiction: a read-only polling tool is described while annotations mark it not read-only. Although the description otherwise adds rich behavioral detail about states, coverage, and result matching, the contradiction forces a low score here.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and then organizes polling, state values, result semantics, and coverage details. It is long and somewhat dense, but most sentences earn their place because the tool has no output schema and needs to explain complex status/result behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description still fully explains the returned state values, result content, result_matches_final_stl, partial/coverage fields, plain output, and log_tail behavior. An agent has enough information to poll correctly and interpret the response.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must carry parameter meaning, and it does: run_dir is explained as the run folder with its default, and result is explained as whether to include the result, including setting it false for state only.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: show the state of a verify job and, when done, its result. It also distinguishes this from verify_run by explaining when a stale result means verify_run should be rerun.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says to call the tool again to watch the job, names the terminal states that end polling, warns that no callback will occur, and directs the agent to run verify_run again when result_matches_final_stl is false. That gives clear when-to-use and alternative guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 32 tool updatesv0.5.0
    • First observedapply_marks
    • First observedbuild_regions
    • First observedcase_status
    • First observedcheck_problem
    • First observedcleanup_list
    • First observedcompare_runs
    • First observedenvironment
    • First observedexport_step
    • First observedfind_features
    • First observedfind_material
    • First observedfind_printer
    • First observedlist_runs
    • First observedmarks_to_hints
    • First observedprint_check
    • First observedprinter_materials
    • First observedratchet_approve
    • First observedratchet_run
    • First observedratchet_status
    • First observedrecord_brief
    • First observedrender_part
    • First observedrun_history
    • First observedrun_result
    • First observedrun_status
    • First observedrun_topopt
    • First observedsave_material
    • First observedsave_preferences
    • First observedsave_printer
    • First observedshow_problem
    • First observedstop_run
    • First observedteam_guide
    • First observedverify_run
    • First observedverify_status

TDQS

A4/5.0

Scored across 32 tools

Disambiguation4/5

Most tools map cleanly to one workflow stage (setup, run control, verification, print, materials, cleanup), so an agent can usually pick correctly. The only plausible hesitation points are run_status vs run_result and check_problem vs show_problem, and their descriptions explicitly distinguish the pairs.

Naming Consistency5/5

All names use consistent lowercase snake_case, mostly in verb_noun form or clear domain noun form. Family prefixes such as run_, verify_, ratchet_, and save_ are used coherently.

Tool Count2/5

32 tools is above the heavy range and imposes real navigation burden even for this broad domain. Each tool covers a real step, but the set is large enough that an agent must search across many adjacent lifecycle operations.

Completeness5/5

The surface covers the full lifecycle: problem construction and checking, run start/stop/status/result, comparison and history, independent verification, print checks, materials and printer lookup, marks/cleanup/ratchet workflows, rendering, and STEP export. No obvious dead end or missing core operation is apparent.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to convert raw STL mesh files into production-grade STEP AP242 solid B-Rep models and compact semantic CAD Features JSON, with sub-second deterministic processing and high mathematical fidelity.
    28
    PolyForm Noncommercial 1.0.0
  • A
    license
    A
    quality
    A
    maintenance
    Enables an LLM to design parametric 3D parts in pure NumPy and verify they are actually printable before exporting them. Provides topology checks (watertightness, genus, shell count, wall thickness), self-rendered views, and gated STL/OBJ export that refuses broken solids.
    7
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to design, modify, and verify exact B-rep 3D CAD models by running build123d scripts on an OpenCascade kernel, with live three.js preview, collision and FDM printability checks, text-based spatial perception, user notes/sketch annotations, version history, and one-click export to OrcaSlicer.
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Lets an AI assistant check and repair STL/3MF meshes stored on your own computer, reporting holes, flipped faces, inside-out shells, non-manifold edges and duplicate triangles and writing a fixed copy beside the original. Everything runs locally, so the files are never uploaded and the original is never overwritten.
    334 npm
    MIT