Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions cookbook/snippets/assembly-connector-and-revolute-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
id: assembly-connector-and-revolute-mate
title: Declare a connector and join parts with a revolute mate
tags: [assembly, connector, mate, revolute, hinge, joint]
keywords:
- assembly with parts connectors and mates
- how do I declare a connector
- revolute joint
- hinge
- axis connector origin
- pivot joint between parts
- declare connector and mate
when_to_use: >-
The model has multiple mechanical parts (not a single fused body) that
need a named pivot between them. Declare an axis connector on each part
with partRef.connector(name, { type: 'axis', origin: { kind: 'vec3', value:
[...] }, axis: [...] }), then join the connectors with arm.mate(name,
'partA.conn', 'partB.conn', 'revolute', { limitsDeg: [min, max] }). This is
the canonical assembly-topology vocabulary for hinges, elbows, and any
revolute joint — connector origins must use the tagged
{ kind: 'vec3', value: [...] } form, not a bare [x, y, z] array.
---

```typescript
const arm = assembly('two-link-arm');

const base = arm.part('base', box(40, 40, 16));
const link = arm.part('arm', box(10, 40, 6).translate(0, 20, 0));

base.connector('pivot', { type: 'axis', origin: { kind: 'vec3', value: [5, 20, 16] }, axis: [0, 1, 0] });
link.connector('pivot', { type: 'axis', origin: { kind: 'vec3', value: [0, 0, 0] }, axis: [0, 1, 0] });

arm.mate('elbow', 'base.pivot', 'arm.pivot', 'revolute', { limitsDeg: [0, 90] });

return arm.solvedModel({ elbow: 45 });
```
34 changes: 34 additions & 0 deletions cookbook/snippets/clamshell-hinge-two-part-assembly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
id: clamshell-hinge-two-part-assembly
title: Clamshell hinge between a base and a lid, joined by a revolute mate
tags: [assembly, connector, mate, revolute, hinge, joint]
keywords:
- hinge
- revolute joint
- clamshell hinge
- lid pivots on base
- assembly with connectors and mates
- declare a connector
- hingeAxis connector
when_to_use: >-
You are modeling a laptop-lid-style clamshell hinge, or any assembly
where one rigid body swings about a fixed pivot line on another rigid
body. Declare a matching axis connector on both bodies along the
physical hinge line, then join them with a revolute mate and limitsDeg
to bound the swing angle. Relevant for hinge, revolute joint, or
assembly with connectors and mates.
---

```typescript
const arm = assembly('clamshell-hinge');

const base = arm.part('base', box(300, 200, 12).translate(0, 0, 6));
const lid = arm.part('lid', box(300, 200, 6).translate(0, 100, 3));

base.connector('hingeAxis', { type: 'axis', origin: { kind: 'vec3', value: [0, -100, 12] }, axis: [1, 0, 0] });
lid.connector('hingeAxis', { type: 'axis', origin: { kind: 'vec3', value: [0, 0, 0] }, axis: [1, 0, 0] });

arm.mate('hinge', 'base.hingeAxis', 'lid.hingeAxis', 'revolute', { limitsDeg: [-15, 135] });

return arm.solvedModel({ hinge: 90 });
```
8 changes: 7 additions & 1 deletion cookbook/tags.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,11 @@
"joinery",
"bracket",
"stacking",
"symmetry"
"symmetry",
"assembly",
"connector",
"mate",
"revolute",
"hinge",
"joint"
]
44 changes: 44 additions & 0 deletions src/agent/mcp/tools/mechanismCookbook.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2026 Andrii Shylenko and kernelCAD contributors
//
// KC-10: lookup_cookbook could not see any mechanism/assembly content — every
// query about connectors, mates, or hinges returned single-body geometry
// snippets (top hit for "assembly with parts, connectors and mates" was
// mirror-half-part). This asserts the cookbook corpus now surfaces the
// mechanism snippets for the queries that used to fall through to
// single-body geometry.
import { describe, it, expect } from 'vitest';
import { lookupCookbookTool } from './lookupCookbook';

const MECHANISM_SNIPPET_IDS = new Set([
'assembly-connector-and-revolute-mate',
'clamshell-hinge-two-part-assembly',
]);

describe('lookupCookbookTool — mechanism/assembly coverage (KC-10)', () => {
const queries = [
'assembly with parts connectors and mates',
'hinge',
'revolute joint',
'how do I declare a connector',
];

for (const query of queries) {
it(`returns a mechanism snippet for "${query}"`, async () => {
const r = await lookupCookbookTool({ query });
expect(r.ok).toBe(true);
expect(r.hits!.length).toBeGreaterThan(0);
const ids = r.hits!.map((h) => h.id);
expect(ids.some((id) => MECHANISM_SNIPPET_IDS.has(id))).toBe(true);
});
}

it('the returned mechanism snippet shows the tagged connector-origin form, not a bare array', async () => {
const r = await lookupCookbookTool({ query: 'how do I declare a connector' });
const hit = r.hits!.find((h) => MECHANISM_SNIPPET_IDS.has(h.id));
expect(hit).toBeDefined();
expect(hit!.body).toContain("origin: { kind: 'vec3', value:");
expect(hit!.body).toMatch(/type: 'axis'/);
expect(hit!.body).toMatch(/'revolute'/);
});
});
2 changes: 2 additions & 0 deletions src/agent/skills/kernelcad-authoring/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -828,8 +828,10 @@ When you need a canonical pattern, call MCP tool `lookup_cookbook(query, k?)` to

| ID | Trigger |
|---|---|
| assembly-connector-and-revolute-mate | The model has multiple mechanical parts (not a single fused body) that need a named pivot between them. Declare an axis connector on each part with partRef.connector(name, { type: 'axis', origin: { kind: 'vec3', value: [...] }, axis: [...] }), then join the connectors with arm.mate(name, 'partA.conn', 'partB.conn', 'revolute', { limitsDeg: [min, max] }). This is the canonical assembly-topology vocabulary for hinges, elbows, and any revolute joint — connector origins must use the tagged { kind: 'vec3', value: [...] } form, not a bare [x, y, z] array. |
| blind-pocket-from-top | You want a pocket cut into the top face only — the cylinder is shorter than the plate so it does not reach the bottom face. |
| chamfer-rotated-face | You rotated a primitive and now want to chamfer one of its canonical faces by name (face-name semantics survive transforms). |
| clamshell-hinge-two-part-assembly | You are modeling a laptop-lid-style clamshell hinge, or any assembly where one rigid body swings about a fixed pivot line on another rigid body. Declare a matching axis connector on both bodies along the physical hinge line, then join them with a revolute mate and limitsDeg to bound the swing angle. Relevant for hinge, revolute joint, or assembly with connectors and mates. |
| clearance-hole-through-plate | You need a through-hole sized for a bolt with a small clearance margin; cylinder height extends beyond the plate so the cut is unambiguous. |
| extrude-rounded-rect-plate | You want a flat plate with rounded corners; use the dedicated rounded-rect extrude rather than building corners by hand. |
| fillet-face-after-subtract | After subtracting a hole or pocket, you want to round only the rim of the resulting opening — not every edge in the part. |
Expand Down
Loading