Found while building an out-of-tree scripting plugin from scratch against this doc and the actual ocs_plugin_api/host source. Two categories: Fixed outright (docs/examples didn't match the real code): - The worked CadModule example returned Vec<RibbonGroup> from ribbon_groups(); the real trait requires &[RibbonGroup] - the example wouldn't compile. Fixed with the OnceLock pattern the host's own benchmark code already uses. - Reconciled a contradiction between "process isolation removes the need for a shared Rust ABI" and the exact-rustc_version requirement described a few paragraphs earlier in the same doc. - The roadmap's "Next" list still had external automation as unstarted; --mcp/--serve are real and operational (src/cli.rs, src/mcp.rs). - Added the missing plugin.toml to docs/plugin-template-v2 (its own DESIGN.md already claimed one could be installed). - Documented that plugin-template's CI floats rust-toolchain@stable, which doesn't guarantee matching the host's exact rustc - added acadrust_source to both templates' plugin.toml plus the release.yml step that fills it from Cargo.lock's resolved acadrust source, alongside the existing rustc_version fill. Flagging for your call, not fixed here (found the behavior, not sure it's the intended one, prefer to ask than guess at a fix): - acadrust_compatible()'s ABI gate only runs at all if plugin.toml declares acadrust_source - an undeclared field is silently treated as compatible, unlike rustc_version (undeclared = incompatible). The same shortcut appears in two places: ExternalPlugin::acadrust_compatible (src/plugin/external.rs) and the inline check inside fetch_release_info (src/plugin/marketplace.rs). If this is deliberate (e.g. back-compat with manifests from before the field existed), no action needed beyond a comment; if not, both call sites need the same fix. - The command line still uppercases typed/pasted input even with the `>` literal-spaces prefix (Message::CommandInput, src/app/update/mod.rs) - `>` only stops a space from auto-submitting the line, it doesn't skip `s.to_uppercase()`. A plugin command needing a case-sensitive typed argument has no escape today short of automation. - fetch_release_info (src/plugin/marketplace.rs) returns every release under a linked repo with no filter on the manifest's own id field (which it already parses to build ReleaseInfo) - a repo hosting more than one plugin under tag-namespaced releases surfaces all of them mixed together in one plugin's version list. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Open CAD Studio plugin template
A complete scaffold for an external Open CAD Studio add-on. A plugin is its
own repository that builds a cdylib; the host loads it at runtime. Copy this
folder into a new repo and rename the placeholders.
Files
| File | Purpose |
|---|---|
Cargo.toml |
cdylib crate depending on ocs_plugin_api (host feature) |
src/lib.rs |
manifest + CadModule ribbon + BuiltinPlugin + export_plugin! |
plugin.toml |
metadata read by the host (mirrors the manifest) |
.github/workflows/release.yml |
cross-builds the cdylib and publishes a release |
PLUGIN.md |
your command reference + XDATA schemas |
Quick start
- Copy this folder into a new repository.
- Rename
my-plugin/My Plugin/opencad.my_plugin/my_plugin/MP_throughout (Cargo.toml,src/lib.rs,plugin.toml, the workflowasset:names), keepingplugin.tomland theMANIFESTin sync. cargo buildto check it compiles.
Test locally
cargo build --release
mkdir -p "<config>/OpenCADStudio/plugins/opencad.my_plugin"
cp target/release/*my_plugin*.so "<config>/OpenCADStudio/plugins/opencad.my_plugin/"
sed "s|__RUSTC_VERSION__|$(rustc --version)|" plugin.toml > \
"<config>/OpenCADStudio/plugins/opencad.my_plugin/plugin.toml"
Restart Open CAD Studio: the ribbon tab appears and MP_ commands route to your
plugin. (<config> = %APPDATA% / ~/Library/Application Support /
$XDG_CONFIG_HOME.)
Publish
Push a v* tag — the workflow builds the cdylib on Linux/Windows/macOS and
uploads each binary plus plugin.toml to a GitHub Release. Users install it from
the Plugin Manager by linking your owner/repo, or — once your repo is added
to plugins/registry.json
via PR — straight from Available plugins.
The binary must be built with the same toolchain and
ocs_plugin_apiversion as the host (approach B). Seedocs/plugin-architecture.md.