text-to-cad
earthtojake/text-to-cad/AGENTS.md
This repo is a workbench for CAD-related agent skills. Treat skills/ as the product and models/ as the shared fixture/artifact area. main is the only long-lived branch: the source tree, what installers clone, and what releases are cut from. Branch from main and open PRs against main; never push it directly. There is no development symlink layout — every path in the tree is the real file. Do not bump the canonical release version in VERSION during normal development work;…
AGENTS.md16k starsChanged 3 days ago
- Installs packages
# AGENTS.md
This repo is a workbench for CAD-related agent skills. Treat `skills/` as the
product and `models/` as the shared fixture/artifact area.
## Branch First
`main` is the only long-lived branch: the source tree, what installers clone,
and what releases are cut from. Branch from `main` and open PRs against `main`;
never push it directly. There is no development symlink layout — every path in
the tree is the real file.
## Release Workflow
Do not bump the canonical release version in `VERSION` during normal
development work; the `Test` workflow refuses a PR that changes `VERSION` from
any branch but `release/*`. Releases are two GitHub Actions workflows:
- `Prepare Release` (`release-prepare.yml`, manual): opens and merges a release
PR against `main` that bumps `VERSION`, the derived metadata and every
skill's `cadgen==` pin together.
- `Publish Release` (`release-publish.yml`): fires on the push that merge makes.
Bundles, tests, builds the `cadgen` wheel, installs and exercises it, keeps
the distribution as a workflow artifact, then — on `main` only — uploads to
PyPI, deploys the docs site, and tags (`v<VERSION>`; releases before 0.5.0
are bare `0.4.x` tags) + GitHub-Releases that same merged commit with the
wheel and sdist that went to PyPI attached as release assets.
When asked to publish, make, or ship a release, dispatch `Prepare Release` on
`main`. Never pick the semver bump yourself: if the request does not name patch,
minor, major, or an exact version, ask which one before dispatching. To resume a
run that uploaded the wheel but failed before the tag or the docs deploy, or to
republish the current head, dispatch `Publish Release` on `main` (`publish=false`
leaves the GitHub Release as a draft). `target=build-test` on `Prepare Release`
is the rehearsal — the same PR against `build-test`, whose pushes run `Publish
Release` without PyPI, docs or tag — and is never a release; use it only when the
user explicitly asks to test the pipeline.
The standalone `Deploy Docs` workflow redeploys the docs site from a ref
(default `main`, or a release tag) without running a release.
Skill `requirements.txt` files pin `cadgen==<VERSION>` on `main` itself;
`scripts/release/check-version.sh` asserts every pin equals `VERSION`. A
checkout's editable install reports that same version, so the pin is satisfied
in development too — install `requirements-dev.txt`, never a skill's
`requirements.txt` on its own (that fetches the previous release from PyPI).
`models/` stays on `main` as LFS pointers (`.lfsconfig` excludes it from
default fetches; `.gitattributes` export-ignores it from archives); nothing
installs it. `scripts/github-workflows/check-builds.sh` enforces the shipping
contract on every push: no tracked symlink, no LFS path under `skills/`, no
skill reaching into a repo root. See the Releases section in `CONTRIBUTING.md`
for the full flow, the resume path, the rehearsal, and local/manual fallbacks.
## Repo Map
- `skills/`: agent skills and their references/scripts.
- `.claude-plugin/`, `.codex-plugin/`: agent plugin manifests. The repository
root is the plugin package; its skills are `skills/` directly.
- `models/`: sample and durable CAD/robot-description fixtures.
- `apps/web/`: the CAD Viewer's React client (its backend is `cadgen.viewer`).
- `packages/core`: `@text-to-cad/core`, shared CAD/runtime/client code without React.
- `packages/ui`: `@text-to-cad/ui`, the shared FileViewer, renderers, controls and styles.
- `packages/cadgen`: the published distribution — STEP/GLB/topology generation,
the skill CLI parsers, the CAD Viewer backend + client, and the Node/browser
runtimes it executes.
- `apps/docs/`: documentation site.
- `tests/`: root-owned test suites for skills, packages, viewer services, and
repo-wide policy.
- `scripts/`: durable repo commands grouped by purpose.
## Repo Rules
- Boundaries and design laws live in each package's README: read
`packages/cadgen/README.md` (the laws), `packages/core/README.md`, `packages/ui/README.md`,
`apps/web/README.md`, and `apps/docs/README.md` before changing
generation, rendering, storage, layout, or public interfaces.
- A README holds the laws; the mechanism each law constrains lives one link
away, and the README names the link. Read the README, then follow the one
link — not the tree. What exists:
- `packages/cadgen/`: `STORE.md` (the store contract — sectioned, with a
table of contents), `MEMO.md` (`@memo`, and the process-wide geometric
`Shape` identity it installs), `SNAPSHOTS.md` (snapshot `--debug` timings).
- `packages/core/docs/`: `render-pipeline.md`, `resource-ownership.md`,
`tube-deformation.md`.
- `packages/ui/docs/`: `settings-ui.md` (BINDING for any settings control),
`render-types.md`, `render-mode.md`, `lod.md`, `storage.md`, `backend.md`.
- Ships-alone law: `packages/cadgen` (the built PyPI wheel) works in isolation
outside this repo, so its markdown must not refer to anything outside the
package — enforced by `tests/python/global/test_package_boundaries.py`.
Repo-development guidance for it goes in `CONTRIBUTING.md`.
- Keep root guidance short. Put domain workflows, CLI details, and validation
policy in the relevant `skills/<skill>/SKILL.md` or `references/` file.
- Keep relevant Markdown docs current when changing behavior, commands, or repo
layout, but do not bloat `AGENTS.md`; use it only for durable repo-level
rules and pointers.
- Read `CONTRIBUTING.md` before committing, rebasing, resolving generated-file
conflicts, or bumping release versions.
- A skill must not import another skill, a `skills/` root module, or a
repository-root module, and must not add `skills/`, the repository root, or a
sibling skill directory to `sys.path`, `PYTHONPATH`, `NODE_PATH`, or any other
runtime lookup path. Skills are independent of each other, not of everything.
- Shared runtime comes from the **`cadgen` distribution**. A skill that uses it
names it in its `requirements.txt`, pinned to `VERSION` (the release PR
stamps every pin; the editable install in `requirements-dev.txt` satisfies
it in a checkout). Skills do not vendor it: a skill script is a thin entrypoint whose
parser and behaviour live in `cadgen.cli`, and which fails with the
`pip install -r requirements.txt` hint when cadgen is missing. cadgen carries
the JavaScript it executes too (Node builders, the snapshot browser bundle,
the CAD Viewer client), so a skill ships no runtime of its own. Not every
skill needs cadgen (bambu-labs, dfam-check, dfm, gcode, sendcutsend,
step-parts are cadgen-free); do not add the dependency to a skill that never invokes it.
- Keep samples and manual CAD/robot-description validation artifacts under
`models/`. Automated tests must not read, build or import that sample corpus:
generate small fixtures in fresh temporary directories or use tiny test-owned
fixtures, with their own cache stores and cleanup. Repo `tmp/` is fine.
Enforced by `tests/python/global/test_tests_are_self_contained.py`.
- Every test runs in CI. Each test file is reached by a runner under
`scripts/test/`, every runner is called by a `test.yml` job on the changes that
can break it, and a collector that finds nothing fails the run rather than
reporting a group that never ran. A test no CI job runs is dead: wire it in or
delete it. There are no manual-only test gates. Enforced by
`tests/python/global/test_ci_workspace_selection.py`.
- Tests and CI are short and succinct. Test a contract, a user flow or a fixed bug,
once, at the cheapest level that exercises the real path: a unit or jsdom test
first, a real browser (WebGL) only for what needs one. Await the condition, never
a fixed sleep or a wall-clock bound; a flaky test is fixed or deleted, never
retried. CI time is a budget: the `web` job stays within 7 minutes, and a
change that lengthens any job says what it costs and why in its PR.
- Benchmarks under `scripts/bench/` are manual and their output is never
committed: reports, logs, profiles and screenshots go to an ignored `tmp/`.
Only their pure helper units run in a test runner.
- The Python floor is `requires-python` in `packages/cadgen/pyproject.toml` and
nowhere else. Every cadgen source is parsed against that floor, so syntax
newer than it fails here rather than at `pip install` time on a user's
interpreter; raising the declared minimum relaxes the check automatically.
- Reserve `scripts/` for durable repo commands. Do not write temporary,
one-off, or local-only helper scripts there; use `tmp/` or `/tmp` instead.
- cadgen's packaged runtime (`_runtime/node`, `_runtime/browser`,
`_runtime/viewer`) is BUILT, never committed: the whole directory is
gitignored and ships only inside the wheel. Build it with the one bundle
entry point, `scripts/bundle/bundle.sh`; `bundle.sh --check` builds it and
asserts every required output. Call `scripts/bundle/cadgen-runtime.sh`
directly only when debugging one stage.
- Never let a symlink reach the published tree. Agent installers disagree about
symlinks and one loses data silently: the Skills CLI dereferences them, Claude
Code preserves them, and Codex `plugin add` drops them with no error, shipping
a skill with missing files. `scripts/github-workflows/check-builds.sh` enforces
this; do not relax it.
- The CAD Viewer is `cadgen viewer`: the server is `cadgen.viewer` (Python, in
`packages/cadgen`), the React client's source is `apps/web/` and its build
ships in the wheel at `cadgen/_runtime/viewer` (built, never committed; a
checkout serves `apps/web/dist`). The cad-viewer skill is instructions over that verb.
Nothing in `cadgen.viewer` imports the CAD kernel at module scope — the one
kernel action, importing a foreign STEP, is a compile job in cadgen's build
pool, never work the server process does.
Keep repo-level tooling in `scripts/`, not under `apps/web/`.
- `packages/core` stays non-React. Shared FileViewer/renderers belong in
`packages/ui`; host workflow state belongs in apps. Apps never import another
app and shared packages never import apps. Root npm workspaces consume compiled
package exports; do not add source aliases or nested lockfiles. Preserve app
UI/UX and functionality during restructuring; changes are pure refactors.
- Shared UI must stay platform-agnostic. Apps implement environmental effects;
shared features use injected capabilities and named extension slots. Before
extending these interfaces, read [the viewer host contract](packages/ui/docs/viewer-host.md).
- `packages/cadgen` is the whole distribution, not just the Python: artifact
generation, the CLI parsers behind every skill command (`cadgen/cli`), the warm
build daemon (`cadgen/daemon`), and
the JS/SPA assets it executes (`cadgen/_runtime`, built by
`scripts/bundle/cadgen-runtime.sh`). Skills consume it as an
installed distribution.
- Create lightweight shared Python packages under `packages/` when a helper
should not inherit heavier package dependencies.
- Use path-targeted search, validation, and `git status`; avoid broad scans over
generated CAD/LFS artifacts unless the task requires them.
- Treat `VERSION` as the canonical release version. Do not hand-edit duplicate
package, plugin, lockfile, or Python `pyproject.toml` versions; release
preparation and `scripts/bundle/bundle.sh` stamp them from the canonical
version.
## Environments
- Prefer `./.venv/bin/python` for CAD Python work.
- Keep new branch checkouts and git worktrees lightweight by default. Do not
copy `.venv/` or `models/` through `.worktreeinclude`; recreate `.venv/`
inside the worktree only when Python dependencies are needed for the workflow.
- In Codex or Claude Code worktrees, prefer the skill instructions and scripts
under the current worktree's `skills/` directory over globally installed
skill symlinks from another checkout.
- Hydrate `models/` only when the user asks for it or when the task targets
specific files under `models/`. In a new worktree, make the relevant model
paths real before using them, preferring the local Git LFS cache with
`git lfs checkout <path>` or `git lfs checkout models`. Download missing LFS
objects only when explicitly requested or required after confirming the local
cache is missing them.
- Install dependencies only for the workflow being changed.
- Do not commit `.venv/`, `node_modules/`, caches, `tmp/`, local credentials, or
printer config.
## Checks
Run the smallest path-targeted check that covers the change. Use broad wrappers
when touching shared surfaces or before handoff:
- Code tests: `scripts/test/test.sh` (JS, then Python, then policy).
- Focused runners: `scripts/test/test-js.sh`, `scripts/test/test-docs.sh`,
`scripts/test/test-python.sh`, `scripts/test/test-global.sh`.
`test-python.sh` takes `--select cadgen|viewer|skills|all` and
`--print-weights`; `test-js.sh` takes `--select core|ui|web|all`. See
`scripts/README.md`.
- In GitHub Actions, `test.yml` runs one conditional job per concern. The graph,
stable required check names and workspace install recipes are in
`CONTRIBUTING.md#ci`. Core changes reach all consumers; UI reaches web; app
changes do not run unrelated apps. Manual dispatch runs all jobs.
- Canonical release version: `scripts/release/check-version.sh`
- Packaged runtime builds and is complete: `scripts/bundle/bundle.sh --check`
- CAD Viewer or shared packages: build exports with `npm run build:packages`,
then `npm --prefix packages/core test`, `npm --prefix packages/ui test`,
`npm --prefix apps/web run test`, `npm --prefix apps/web run build`.
The Viewer is two languages and `npm run test` covers only the client — the
backend's suite is `tests/python/packages/cadgen/viewer`, run by
`scripts/test/test-python.sh`. Touching `cadgen/viewer/` means running that.
- Docs site: `npm --prefix apps/docs run check`
- Targeted Python tests: `./.venv/bin/python -m unittest <changed test paths>`
When a task changes what the bundlers consume, run `scripts/bundle/bundle.sh`
and confirm the change lands in the built runtime. There is nothing to commit:
`_runtime/` is gitignored end to end, so what a reviewer reads is the source and
what a user gets is the wheel the release builds from it.
## CAD Viewer
The app-facing playbook lives in `apps/web/README.md`: launcher contract
(reuse, ports, `--new`), dev vs prod, and the catalog/link-verification
gotchas. The repo-side half — the lightweight-worktree recipe and
root workspace dependencies — lives in `CONTRIBUTING.md` under "Viewer Development
In This Repo". Read them before starting, stopping, or debugging a Viewer.
Never stop an instance you did not start; packaged-runtime checks go
through `scripts/bundle/bundle.sh`.
## Git And LFS
CAD exchange files, generated render/topology assets, and `assets/**` may be
LFS-tracked. Never disable LFS filters for `git add`, commits, or other
object-writing operations. Local hooks live in `.githooks` and
delegate build checks through `scripts/git-hooks/pre-commit`.
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
Posts are public.Sign in to post
No one has posted yet. Be the first.

