On-prem CAD-designer Claude agent

A SECOND always-on Claude Code agent on telep-mainframe, dedicated to parametric CAD design in FreeCAD. Modeled on the control-plane operator agent but separate: its own systemd unit, its own tmux socket, its own workspace, and the FreeCAD MCP wired in so it can drive the CAD workstation directly. Pairs with the FreeCAD workstation and its export pipeline.

For Agents

Service: cad-designer.serviceUser=levander, Type=forking, Restart=always, enabled. Workspace: /home/levander/cad-agent/ (own CLAUDE.md persona + .mcp.json). MCP: freecadhttp://127.0.0.1:9876/mcp (local loopback, not the tailnet hairpin) — ✔ Connected. tmux: session cad-designer-telep on a dedicated socket -L cad-designer (NOT the default socket the control-plane uses). Reachable: Claude app Code tab — the spawned session shows as cad-designer-telep. Permissions stay ACTIVE--dangerously-skip-permissions deliberately NOT used.

How to reach it in the Claude app

Open the Code tab. The visible session is named cad-designer-telep (this build sets --remote-control-session-name-prefix cad-designer-telep, so unlike the control-plane’s random …-velvety-star, the spawned session name is deterministic). It shows ✔ Connected · cad-agent · HEAD. Talk to it there to design parts; it drives FreeCAD live and exports through the pipeline.

What it is

  • Runs claude remote-control --name cad-designer-telep --remote-control-session-name-prefix cad-designer-telep --spawn same-dir in a persistent tmux session, working dir /home/levander/cad-agent/.
  • Shares the box’s existing subscription creds (~/.claude/.credentials.json) with the control-plane agent — no separate login. Trust pre-seeded (see below).
  • Has the FreeCAD MCP attached (15 tools), so from the app the user can say “design an X” and it builds geometry in the live FreeCAD GUI and exports 3MF/STL/STEP.

Persona (/home/levander/cad-agent/CLAUDE.md)

Tight CAD-designer brief: parametric CAD in FreeCAD via the MCP (create_object/execute_code/get_view); design for 3D printing on the Bambu H2S (mm, printability, ~0.2 mm fit clearance); the export pipeline (the export_all helper → 3MF/STL/STEP into /exports); exports auto-sync to the Mac (~/cad-exports/) and are browsable at https://cad.taild4189d.ts.net:8080/; noVNC live preview at https://cad.taild4189d.ts.net/; and the Bambuddy handoff (model 3MF → Bambu Studio slice → Bambuddy virtual printer, 2026-08-08-bambuddy-deploy-plan). Carries the house rules (no code comments, never commit, DRY).

MCP config

/home/levander/cad-agent/.mcp.json:

{
  "mcpServers": {
    "freecad": { "type": "http", "url": "http://127.0.0.1:9876/mcp" }
  }
}

The agent is ON the mainframe, so it uses the local loopback endpoint 127.0.0.1:9876/mcp (the mcp-proxy container’s host port) — NOT the tailnet cad:8443/mcp that the Mac session uses. Trust + auto-enable pre-seeded in ~/.claude.json under the /home/levander/cad-agent project: hasTrustDialogAccepted=true, enableAllProjectMcpServers=true, enabledMcpjsonServers=["freecad"] — so it attaches the MCP with no prompt.

Verify: cd /home/levander/cad-agent && claude mcp listfreecad: … ✔ Connected.

systemd unit

/etc/systemd/system/cad-designer.service — same shape as control-plane.service EXCEPT the tmux calls use a dedicated socket -L cad-designer:

[Service]
Type=forking
User=levander
WorkingDirectory=/home/levander/cad-agent
Environment=HOME=/home/levander
Environment=PATH=/home/levander/.local/bin:/usr/bin:/bin
ExecStartPre=-/usr/bin/tmux -L cad-designer kill-session -t cad-designer-telep
ExecStart=/usr/bin/tmux -L cad-designer new-session -s cad-designer-telep -d '/home/levander/.local/bin/claude remote-control --name cad-designer-telep --remote-control-session-name-prefix cad-designer-telep --spawn same-dir'
ExecStop=/usr/bin/tmux -L cad-designer kill-session -t cad-designer-telep
Restart=always
RestartSec=10

Dedicated tmux socket is REQUIRED — this is the one real gotcha

The control-plane agent already owns the default tmux server. A Type=forking unit that runs tmux new-session -d on that same server forks NO new daemon (the server already exists), so systemd’s main-PID guess fails, it declares the unit failed, runs ExecStop (which kills the session) and enters a restart/thrash loop — the session never persists. Giving cad-designer its OWN socket (-L cad-designer) makes tmux new-session start a fresh server daemon that systemd can track → the session persists, NRestarts=0, active (running). Inspect it with tmux -L cad-designer ls / tmux -L cad-designer attach -t cad-designer-telep.

Operate / check

command ssh levander@192.168.1.123
systemctl status cad-designer.service          # active (running), enabled
tmux -L cad-designer ls                         # cad-designer-telep: 1 windows
tmux -L cad-designer capture-pane -pt cad-designer-telep | tail   # should show ✔ Connected
sudo systemctl restart cad-designer.service
cd /home/levander/cad-agent && claude mcp list  # freecad ✔ Connected

If the app shows an OAuth error or the pane churns Reconnected after Ns: same root cause and fix as the control-plane — the shared ~/.claude/.credentials.json tokens are zeroed; fix with an interactive claude login on the box (real TTY), no restart needed. See 2026-08-22-control-plane-oauth-zeroed-creds. Because the creds are shared, fixing it once heals both agents.

Relationship to the control-plane operator agent

control-plane (operator)cad-designer (this)
Servicecontrol-plane.servicecad-designer.service
Workspace/home/levander/obsidian (the vault)/home/levander/cad-agent
tmux socketdefault-L cad-designer (dedicated)
Session name in apprandom (…-velvety-star)cad-designer-telep (fixed)
MCPnone neededfreecad @ 127.0.0.1:9876/mcp
Purposehost ops / homelab adminparametric CAD + export
Credsshared ~/.claude/.credentials.jsonshared (same file)

Both keep tool permissions ACTIVE (no --dangerously-skip-permissions) — approval in the app is the human-in-the-loop guardrail, and on this passwordless-sudo box an approved action is instant root. Pre-seeding trust widens launch, not authority. Same posture as 2026-08-08-telep-master-agent-impl.