⚡ TL;DR — an AI panel inside Houdini: type "make a box," get a real node. Every action is ordinary Houdini, so Ctrl+Z takes it back — and it keeps receipts, not magic. Five engines, 115 tools. Install ↓ in ~5 min.
🧪 The moat, in one line: every other Houdini copilot reasons from docs and memory — SYNAPSE probes the running Houdini and commits what it finds (six truth catalogs and counting: wiring, Solaris context, capability, readiness, live cook behavior, and now perception truth — the render receipt). Docs drift. Probes don't.
✦ The idea, in plain terms
SYNAPSE lives inside Houdini and turns plain English into real work:
- 🧠 It works inside Houdini, not off to the side — the assistant runs in Houdini itself, so there's no separate app to launch and nothing to wait on; it answers right where you're working.
- 🔁 Your words become real nodes — every request is just a normal Houdini action. Don't like it? Ctrl+Z takes it back.
- 🧾 It keeps the receipts — changes are ordinary Houdini actions you can undo, and the audited
/mcppath records a receipt for every one, so you can see what it did and why. That's the differentiator — not magic, receipts. - 🔌 Pick your AI · 115 tools — choose Claude · Gemini · NVIDIA Nemotron · Ollama (local) · Custom in the panel and switch whenever you like.
- 📜 Free to use (MIT license) (LICENSE) with patent-pending methods (PATENTS) — the license covers the code, not the patents.
✦ Map — you are here
| You want… | Read… |
|---|---|
| The 30-second pitch | The idea, in plain terms (above) + What it is |
| What's new in v5.33.0 | New in v5.33.0 — the main thread never waits on itself: a whole class of permanent Houdini freeze removed, lint-enforced, live-verified |
| What still holds the UI (and why) | The honest limits — inside the v5.33.0 section |
| What a render actually proves | The render receipt |
| How AI network-building stays safe | Propose → validate → build |
| To install it | Install — 5 minutes |
| The architecture | How it works — inside-out |
| Every release + per-tool detail | CHANGELOG.md |
✦ What it is
A docked SYNAPSE panel inside Houdini. You type what you want — "make a box", "create a solaris network ending with rendersettings using karma xpu" — and it builds it in your live scene. Chat in, real nodes out.
- ⚡ In-process — the agent runs in Houdini's own Python; tools are direct
hou.*calls, not a slow round-trip bridge. - ↩️ Undo-safe — everything it does is an ordinary Houdini action. Ctrl+Z undoes it. On the audited
/mcppath every mutation leaves a provenance record; the live WebSocket path records observe-only envelopes. - 🔌 Multi-provider — pick Claude · Gemini · NVIDIA Nemotron · Ollama · Custom right in the panel; swap engines mid-session.
- 🎬 Built for the work — SOPs, Solaris / USD, Karma, COPs, PDG / TOPs, MaterialX — 115 tools.
✅ "make a box" → a real geo node, confirmed on graphical Houdini 22.0.368. (H21 code paths are retained and major-aware, but H21 is no longer installed here, so H22.0.368 is the only live-tested build.)
%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#E8963B','primaryTextColor':'#1A1208','primaryBorderColor':'#9C5A10','lineColor':'#7A4310','secondaryColor':'#EEA958','tertiaryColor':'#F2BC77','edgeLabelBackground':'#F2BC77','clusterBkg':'#F2BC77','clusterBorder':'#9C5A10'}}}%%
flowchart LR
ART["Artist<br/>'make a box'"]:::artist --> PANEL["SYNAPSE panel<br/>rail · CHAT · author token"]:::panel
PANEL -->|"Claude · Gemini · Nemotron · Ollama · Custom"| LOOP["Agent loop<br/>chosen engine + 115 tools"]:::panel
LOOP -->|"tool_use"| EXEC["Tool executor<br/>(main thread)"]:::panel
EXEC --> BR["Handler<br/>undo-wrapped · integrity"]:::bridge
BR -->|in-process call| HOU[("hou.*<br/>node created")]:::hou
BR -.provenance.-> LEDGER["IntegrityBlock trail<br/>audited /mcp + live envelope"]:::side
BR -.timing.-> METRICS["Latency metrics<br/>histograms → Prometheus"]:::side
BR -.needs approval.-> GATE["Consent gate<br/>auto-surfaces in CHAT · accept / revert"]:::bridge
GATE -.hands back.-> ART
classDef artist fill:#DE8425,stroke:#7A4310,color:#1A1208
classDef panel fill:#E8963B,stroke:#9C5A10,color:#1A1208
classDef bridge fill:#EEA958,stroke:#9C5A10,color:#1A1208
classDef hou fill:#DE8425,stroke:#6B3A0C,color:#1A1208
classDef side fill:#F2BC77,stroke:#B37A33,color:#1A1208
The panel, briefly (v9.1):
- One CHAT surface — the build review + consent gate auto-surface when a build needs approval. Consent comes to you, then hands back on accept/revert.
- A persistent rail — live state + a Stop that ends the agent loop. It stops the next step; it cannot claw back a Houdini operation already running.
- The author token — engine + model in one rail control.
Aascales only what you read ·/opens a command palette over every tool · a token-only meter.- Bundled Space Grotesk / Space Mono type system.
✦ New in v5.33.0 — the main thread never waits on itself
One class of permanent Houdini freeze is gone: the main thread waiting on itself. That specific class — not freezing in general — was structurally removed rather than made rarer, and a source lint keeps it from coming back. Everything still capable of holding the UI is listed under The honest limits below.
The defect, in plain terms
Houdini has exactly one thread allowed to touch the scene: the main thread. Everything else has to hand work to it and wait.
The vendor helper SYNAPSE used for that handoff — hdefereval.executeInMainThreadWithResult — never checks who is calling it. Called from a background thread it works correctly. Called from the main thread, it puts work in a queue that only the main thread can empty, then parks the main thread waiting for that work.
Houdini waits for itself, forever. No error, no timeout, no recovery — you kill the process. This is vendor-level behavior on Houdini 22.0.368, and it happens every time, not as a race.
SYNAPSE reached that helper from the main thread by two confirmed routes.
What the fix actually was
Nothing new was built. The codebase already had the right primitive — server/main_thread.py::run_on_main, which was immune from the start:
| Caller | What run_on_main does |
|---|---|
| Off the main thread | Posts the work non-blocking, then waits on a per-call result holder with a real timeout |
| On the main thread | Short-circuits to a direct call — never queues, so it can never wait on itself |
The fix was deleting the nine call sites that bypassed it. A line-scoped source lint (tests/test_marshal_lint.py) now fails the build if the unsafe helper reappears anywhere.
👻 A finding inside the finding: three of those nine called
hdefereval.executeInMainThread— a function that does not exist on H22.0.368. Confirmed against the live runtime. They had been failing silently.
Verified on a running Houdini, not a stub
Live session: H22.0.368, PID 64396, identity-probed before any repro was attempted, so the results can't be a stale-code false pass.
| Check | Result |
|---|---|
run_on_main called from the main thread |
0.014 ms, inline, returned — the identical shape used to park forever |
houdini_capture_viewport over /mcp (a confirmed pre-fix deadlock path) |
Returned twice; Responding=True throughout; bridge served the next turn |
| Deliberate 6-second main-thread hold | Telemetry fired with exact attribution (fast_path_2, 6.0004 s vs a 5.0 s budget) · violations 0 · next turn served 22 µs later |
| ~25-call soak — 5 concurrent read-only, 4 concurrent mutating | Every call returned its own payload (no result swapping) · violations 0 · stack dumps 0 · zero freezes |
That last row closes a second, quieter bug: the vendor helper stored results in module globals, so two concurrent blocking handoffs could hand each other's results back — silently wrong data, no error. No SYNAPSE code path calls that helper any more, and the source lint keeps it out.
- 🟢 4,642 tests passing · 0 failed · 100 skipped. Against the previous release (v5.32.1, 4,571): +71. Against the ratchet floor (
harness/verify/suite_baseline.json, 4,275): +367. Both figures are correct against their own baseline — neither is a bare delta. Zero tests weakened: two test files changed and both were flagged — one pinned the deliberately-removed primitive, and one had gone vacuous (passing while pinning nothing). Both re-anchored and proven able to fail.
The honest limits — read this part
This release removed a specific failure: the main thread waiting on itself. It did not make Houdini un-freezable, and the following are still true:
- 🎬 A render that runs on Houdini's main thread still holds the UI for its duration — and that is the panel path and
/mcp, not the panel alone.- Panel — the Qt slot is the main thread, so the render runs inline there.
/mcp—mcp/server.pymarshals the whole dispatch onto the main thread first, so by the time the render handler runs it detects a main-thread caller and renders inline too (python/synapse/server/handlers_render.py:517, and the caller-path note at:96-107). No session or token flow applies on/mcp— the XPU foreground guard is the only protection there. Budget your/mcprenders accordingly.- WS
/synapse— the one path that is off-main, and the only one that gets the bounded session flow (poll-based status, a 60s token cadence). - On the main thread a render can't be made invisible — only made to finish. What changed is real and it is the whole point: a permanent, unrecoverable freeze became a stall bounded by the render's own duration, which completes. Watch your cores or GPU to confirm it's doing real work.
- 🛑 Cancel does not interrupt an operation that is already running. The WebSocket loop reads messages one at a time, so your
cancelqueues up behind the very handler you're trying to cancel. Out-of-band only —scripts/render_watch.ps1, or kill the process. This is the #1 known follow-up and it is not fixed. - 🐕 The watchdog reports and degrades — it cannot un-wedge a stuck main thread. Nothing running inside the process can. Its job is diagnosis plus graceful degradation, never rescue.
- ⏱️ On
/mcp, a long frame can report failure while the render keeps going and writes its file. Check for the output before re-running, or you'll render it twice.
Operator card (start/stop, healthy vs degraded turn signatures, the two env knobs, four failure modes with recovery): docs/sprint_freeze/OPERATOR_CARD.md. The full evidence chain — every blocking wait mapped per thread, the gate log, the eight-item sign-off — is in docs/sprint_freeze/.
%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#E8963B','primaryTextColor':'#1A1208','primaryBorderColor':'#9C5A10','lineColor':'#7A4310','secondaryColor':'#EEA958','tertiaryColor':'#F2BC77','edgeLabelBackground':'#F2BC77','clusterBkg':'#F2BC77','clusterBorder':'#9C5A10'}}}%%
flowchart TB
subgraph NOW ["Now — one marshal, run_on_main"]
direction LR
OFF["Off-main caller<br/>WS · server pool · worker"]:::panel -->|"posts, never blocks main"| POST["Non-blocking enqueue<br/>executeDeferred"]:::bridge
POST --> MAIN1[("Main thread<br/>drains when idle<br/>runs hou.*")]:::hou
MAIN1 -->|"per-call result holder<br/>bounded wait · timeout is real"| BACK["Caller resumes<br/>with its OWN payload"]:::panel
ONMAIN["Main-thread caller"]:::artist -->|"fast path · thread identity checked"| DIRECT["Direct call — inline<br/>0.014 ms · nothing queued"]:::hou
end
subgraph GONE ["Removed — the 9 bypasses · lint-guarded"]
direction LR
LINT["Source lint<br/>this call can't come back"]:::bridge -.blocks.-> MB
MB["Main thread"]:::artist -->|"executeInMainThreadWithResult<br/>NO caller-thread check"| QUEUE["Queue only MAIN can drain"]:::side
QUEUE -.->|"main is now parked,<br/>so it never drains it"| MB
MB -.-> DEAD["Permanent freeze<br/>no error · no timeout · kill the process"]:::side
end
NOW ~~~ GONE
classDef artist fill:#DE8425,stroke:#7A4310,color:#1A1208
classDef panel fill:#E8963B,stroke:#9C5A10,color:#1A1208
classDef bridge fill:#EEA958,stroke:#9C5A10,color:#1A1208
classDef hou fill:#DE8425,stroke:#6B3A0C,color:#1A1208
classDef side fill:#F2BC77,stroke:#B37A33,color:#1A1208
✦ The render receipt — proof, not a screenshot
When SYNAPSE says it rendered your frame, it can show you why it believes that. RETINA is the perception tier: a render doesn't count as done because the tool returned — it counts when the file on disk says so, and then when the pixels that changed are the ones that were supposed to change.
- 🎯 T0 · file truth (live) — did the render actually happen as declared? Products, resolution, AOVs, a completion sentinel written after the pixels, a fingerprint that round-trips.
- 🔍 T1 · scoped delta (live) — the change-mask intersected with the object-ID matte: did the change land inside the thing you asked about, and stay out of everything else.
- 🧾 The receipt is tri-state — pass · fail · inconclusive. It cannot fake green: no manifest reads "no receipt yet" in grey, never a green 100%.
%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#E8963B','primaryTextColor':'#1A1208','primaryBorderColor':'#9C5A10','lineColor':'#7A4310','secondaryColor':'#EEA958','tertiaryColor':'#F2BC77','edgeLabelBackground':'#F2BC77','clusterBkg':'#F2BC77','clusterBorder':'#9C5A10'}}}%%
flowchart LR
ASK["Artist<br/>'swap the crystal to Dark_Glass'"]:::artist --> BUILD["SYNAPSE builds it<br/>undo-safe · recorded"]:::panel
BUILD --> RENDER["Karma render<br/>beauty + object-ID AOV"]:::panel
RENDER -->|"EXR + .done sentinel<br/>(husk_postframe, +5ms after pixels)"| T0["T0 · file truth ✓ LIVE<br/>rendered? right res/AOVs?<br/>fingerprint round-trips?"]:::hou
T0 -->|"pass / inconclusive"| T1["T1 · scoped-delta ✓ LIVE<br/>change-mask ∩ ID-matte<br/>containment + SSIM-outside"]:::hou
T1 -->|"pass / fail / inconclusive"| REC["agent.usd receipt<br/>DECISION · VIA · PROOF"]:::side
T1 -.next tiers.-> LADDER["T2 ONNX · T3 VLM<br/>cost-gated escalation"]:::side
REC -.-> ART2["Artist<br/>proof, not a screenshot"]:::artist
classDef artist fill:#DE8425,stroke:#7A4310,color:#1A1208
classDef panel fill:#E8963B,stroke:#9C5A10,color:#1A1208
classDef hou fill:#DE8425,stroke:#6B3A0C,color:#1A1208
classDef side fill:#F2BC77,stroke:#B37A33,color:#1A1208
The full picture — the T1 metric kit, the scoped-delta primitives, the twins, the Rulebook, and the supervisor-layer seams that come next — lives in the v5.29.0–v5.31.0 entries of CHANGELOG.md and in
docs/SYNAPSE_RETINA_BLUEPRINT.md.
✦ H22 — running, verified, expanding
Houdini 22 isn't a milestone SYNAPSE is approaching — it's the build SYNAPSE runs on, with the core transition proven live and the generative expansion spec'd next.
- 🔬 Verified against a running Houdini, not just headless — the live-bridge reconfirm converted the whole drop cycle from provisional to confirmed on the real 22.0.368 interpreter: every merged fix, the memory integrity gate, the PDG event surface, the quarantine re-pins.
- 🧩 The Solaris wiring layer is H22-native — a major-aware connectivity catalog (mirroring the per-major symbol-table pattern) means
wire_by_labeland the graph validator resolve H22 truth on H22 and H21 truth on H21, so proposed networks validate against the build you're actually running. - 📋 The port-wave plan (
docs/PORT_WAVE_MANIFEST.md) — all 115 registry tools mapped into 11 sub-waves, each gated: gatewarden admits → forge builds in an isolated worktree → an assayer probes every symbol against the live build → a hostile crucible pass hunts for behavior drift → a human merges. The pilot wave is merged; the rest are unblocked and sequenced. - 🌋 The Copernicus expansion, spec'd and ratified (
docs/SYNAPSE_COPERNICUS_EXPANSION.md) — the read/analysis and node-API layers are deep and live-verified; the generative frontier (scaffold rebuilds, heightfield/terrain emission, neural COP nodes with model/GPU preflight honesty) is now a live-probed build spec, the next cycle's work. - 🤝 APEX MCP boundary contract — Houdini 22 keynote-announced a rigging-scoped first-party MCP preview (not shipped in 22.0). The ratified boundary (
docs/SYNAPSE_H22_BOUNDARY.md) holds: SYNAPSE never competes with it; its differentiators — in-process perception, undo-wrapped mutation, provenance, substrate memory — remain unclaimed by anything SideFX shipped. - 🌀 Cook-behavior diffs, live — the diagnostic-truth catalogs are build-stamped and major-agnostic; on H22 they re-probed with zero code edits, turning how H22 changed cook behavior into a diffable artifact instead of forum anecdotes.
The discipline that got here: nothing merged on any agent's self-report — forge builds, a hostile crucible pass attacks what it didn't build, and every cycle is post-merge suite-re-verified. When a "loud-error" fix was caught only ⅓-implemented, it looped to a Pass-3 rather than shipping. Receipts, not vibes — including the agent's own.
%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#E8963B','primaryTextColor':'#1A1208','primaryBorderColor':'#9C5A10','lineColor':'#7A4310','secondaryColor':'#EEA958','tertiaryColor':'#F2BC77','edgeLabelBackground':'#F2BC77','clusterBkg':'#F2BC77','clusterBorder':'#9C5A10'}}}%%
flowchart LR
DROP["Drop + drop-week<br/>9 runbook artifacts"]:::hou --> ROADMAP["CTO roadmap<br/>silent-break register"]:::panel
ROADMAP --> FIX["Fix cycles<br/>forge → assay → crucible"]:::bridge
FIX -->|"merged + suite-reverified"| MERGED[("master<br/>4,642 / 0")]:::hou
MERGED --> LIVE["Live-bridge reconfirm<br/>32 verdicts → VERIFIED-LIVE"]:::bridge
LIVE -->|"proven on running 22.0.368"| DEMO[("H22-native<br/>Solaris · COP · memory")]:::hou
LIVE -.hostile pass finds a risk.-> NEXT["New fix cycle<br/>ratified · gated"]:::side
NEXT -.-> FIX
DEMO -.next.-> EXPAND["Copernicus expansion<br/>scaffold · terrain · neural (spec'd)"]:::side
classDef panel fill:#E8963B,stroke:#9C5A10,color:#1A1208
classDef bridge fill:#EEA958,stroke:#9C5A10,color:#1A1208
classDef hou fill:#DE8425,stroke:#6B3A0C,color:#1A1208
classDef side fill:#F2BC77,stroke:#B37A33,color:#1A1208
✦ The utility flywheel — probe-verified truth on a loop
SYNAPSE improves itself on a loop: ground the AI's Houdini knowledge in probe-verified truth → review its own code against that truth → wire the truth into the live path. Nothing enters the live path on memory alone — memory drifts; probes don't. Every cycle runs the same EXPLORE → REVIEW → SCAFFOLD contract; a human ratifies each new cycle; and where a catalog and a code comment disagree, the catalog wins.
Three cycles have shipped — three kinds of truth (with capability + readiness catalogs behind them):
-
🔌 ① Wiring truth — how nodes connect.
host/introspect_connectivity.pyinstantiates 282 node types headless and records their real input/output counts + slot labels → a committed, integrity-checked catalog.wire_by_label()(python/synapse/core/wiring.py) resolves inputs by probed label, never remembered index — fail-loud on an unknown label/type.- The validator's slot-semantic checks (P3e) reject an edge into an input the type doesn't have.
- Receipts: the review sweep ran 141 sites, 0 critical; the cycle fixed 2 known miswires (swapped solver inputs).
-
🧭 ② Solaris context truth — what the nodes are.
- A corpus-authored, probe-cross-checked LOP / Solaris knowledge catalog teaches the validator the semantics wiring truth can't see.
- It hard-rejects phantom LOP types the model reaches for out of SOP habit — there is no
gridorplaneLOP (use acube). - It advises when an
assignmaterialhas no material source upstream (amateriallibrary, or areference/sublayerlayer that already authors the materials). - Receipts: 20 checks, 0 critical; the ordering rule was softened from a hard error to an advisory after adversarial review caught it would false-reject valid reference/sublayer material graphs.
-
🌀 ③ Diagnostic truth — what the scene does when poked (new in v5.21.0).
- Perturbation probes catalog live dirty-propagation, recook triggers, and time-dependence per context (SOP/LOP/COP/DOP) — the one truth class no external LLM can hold, because it only exists as live cook-state.
- Receipts: the API probe caught the track's own spec citing H18-era phantom spellings (the cook surface lives on
hou.OpNode, nothou.Node); the catalog's first run captured a real divergence — a COP rewire dirties upstream nodes SOP semantics say it shouldn't. - Staged next:
synapse_explain_recook— ask "why did this recook?" and get an answer cited to a probe trial.
%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#E8963B','primaryTextColor':'#1A1208','primaryBorderColor':'#9C5A10','lineColor':'#7A4310','secondaryColor':'#EEA958','tertiaryColor':'#F2BC77','edgeLabelBackground':'#F2BC77','clusterBkg':'#F2BC77','clusterBorder':'#9C5A10'}}}%%
flowchart LR
EXP["EXPLORE<br/>probe-verified ground truth<br/>live probe · or probe-checked corpus"]:::hou -->|"committed, integrity-checked catalog"| REV["REVIEW<br/>sweep the code vs the catalog<br/>0 critical"]:::bridge
REV -->|"findings → fixes"| SCAF["SCAFFOLD<br/>truth into the live path<br/>wire_by_label · validator P3e + LOP · test pins"]:::panel
SCAF -->|"new truth classes"| NEXT["Queue<br/>human ratifies each new cycle"]:::side
NEXT -->|"cycle N+1 · so far: ① wiring · ② Solaris context · ③ diagnostic (cook truth) · ④ H22 discovery re-sweep (ran — 77 candidates) · queued: the port-wave fix cycles"| EXP
classDef panel fill:#E8963B,stroke:#9C5A10,color:#1A1208
classDef bridge fill:#EEA958,stroke:#9C5A10,color:#1A1208
classDef hou fill:#DE8425,stroke:#6B3A0C,color:#1A1208
classDef side fill:#F2BC77,stroke:#B37A33,color:#1A1208
✦ Propose → validate → build — how AI network-building stays safe
SYNAPSE never builds a network on the model's word alone. Every plan is checked against your live scene and probed ground truth before a single node is created — and the build itself is one undo group.
- 📝 Propose — the model lays the whole network out first: every node, every wire, on paper.
- 🔎 Validate against your live scene — every input exists, every wire fits its input type, the parent network and every referenced node are really there, the plan is a DAG, and names don't collide. If a wire would land on an input you've already connected, validation halts — it never quietly severs your work.
- 📐 Validate against probed truth (P3e) — the wiring catalog rejects an edge into an input index the node type doesn't have, and a slot label that resolves to a different index. Memory doesn't get a vote; the probe does.
- 🧭 Validate against Solaris knowledge — a corpus-authored, probe-cross-checked catalog rejects phantom LOP types (there is no
grid/planeLOP — use acube) and flags a missing material source upstream ofassignmaterial. Context the wiring truth can't see. - 🔨 Build — one undo group — an unconditional TOCTOU re-validate first (a node deleted since propose halts with zero mutation), then create → set parms → wire → read back, all inside a single
hou.undos.group. One Ctrl+Z reverts the whole build. - 🛟 Rollback on failure — if the build trips mid-way, it destroys the partial nodes inside the undo group. Zero net mutation, a structured
FAILEDresult, no orphan nodes. - 🧾 Receipts — every build writes an
agent.usdrecord: decision, reasoning, revert path.
It also wires Solaris the way production expects — the Component Builder pattern for assets, the proper rendersettings → render terminal, layered scene assembly, and the actual merge/sublayer strength rule (higher input index wins).
🕰️ Historical note on that probe. The production-wiring correction was originally live-probed on 21.0.671 — a build no longer installed here, so nothing in this release is verified against it. The Solaris knowledge catalog has since been re-probed on 22.0.368 and made major-aware (v5.29.0, C-U5): light names and the drifted
assignmaterialparm resolve against the build you are actually running, and the stale H21 per-shape light entries were removed rather than carried forward.
Verified end-to-end on live Houdini 22.0.368 (originally proven on 21.0.671) — build, single-undo revert, TOCTOU halt, and forced-failure rollback all pass; the wiring catalog is now major-aware, so validation resolves against whichever build you run.
%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#E8963B','primaryTextColor':'#1A1208','primaryBorderColor':'#9C5A10','lineColor':'#7A4310','secondaryColor':'#EEA958','tertiaryColor':'#F2BC77','edgeLabelBackground':'#F2BC77','clusterBkg':'#F2BC77','clusterBorder':'#9C5A10'}}}%%
flowchart LR
ASK["Artist<br/>'build a karma setup'"]:::artist --> PROP["Propose<br/>nodes + wires, on paper"]:::panel
PROP --> VAL["Validate<br/>vs your live scene · vs the wiring catalog (P3e) · vs the Solaris knowledge catalog<br/>inputs · wire types · slot labels · phantom LOP types · material-source ordering · occupied inputs"]:::bridge
VAL -->|"all clear · parked"| BUILD["Build — one undo group<br/>create → wire → read back"]:::hou
VAL -.->|"something's off"| STOP["Stop · nothing touched"]:::side
BUILD --> NODES[("Real nodes<br/>single Ctrl+Z reverts")]:::hou
BUILD -.provenance.-> REC["agent.usd receipt<br/>decision · reasoning · revert"]:::side
classDef artist fill:#DE8425,stroke:#7A4310,color:#1A1208
classDef panel fill:#E8963B,stroke:#9C5A10,color:#1A1208
classDef bridge fill:#EEA958,stroke:#9C5A10,color:#1A1208
classDef hou fill:#DE8425,stroke:#6B3A0C,color:#1A1208
classDef side fill:#F2BC77,stroke:#B37A33,color:#1A1208
✦ Earlier releases — the short version
Each row is one release's headline; the full record lives in CHANGELOG.md.
| Release | Headline |
|---|---|
| v5.32.x | The render path is bounded — every render tool used to funnel through one unbounded main-thread block. The WS path now renders through a bounded session flow (single-flight tokens, pollable status, a 60s cadence), and an XPU foreground guard refuses to launch a render inline against a cold OptiX shader cache — the condition that turned a bounded render into a multi-minute stall. Plus BLACKBOX: a session that dies silently leaves a capsule of everything in flight, and the next session detects it on startup; render_watch.ps1 watches a stuck render from outside the process. (v5.32.1 reconciled the release metadata and refreshed the demo script to H22 reality.) |
| v5.27.0 | RETINA: the render receipt begins (M0) — the governing blueprint for perception truth (truth cycle ⑤) committed and reconciled clean; a zero-cv2 host boundary pin before any perception code; two official-doc cross-references (HDK/HAPI) that caught a .done-sentinel design flaw on paper. A documentation-and-boundary foundation release. |
| v5.26.0 | H22 live-verified — the whole transition proven against a running Houdini 22.0.368: 32 verdicts flipped provisional→verified-live, the memory integrity gate confirmed at fidelity 1.0 on the reorganized USD, and the last two silent breaks closed (Copernicus solver blocks + the major-aware wiring fold that makes Solaris network-building H22-native). A new sidefx-cto vendor-architect lens; an external "engineering memo" adjudicated-not-obeyed. |
| v5.25.0 | H22 has landed — Houdini 22.0.368 dropped and SYNAPSE ran its own port machinery against it for the first time: the nine-step drop-week runbook complete, a three-lens CTO roadmap over 77 doc-scouted candidates, and the first two cycles merged (the Copernicus planes() silent-data-loss fix + the pilot Dispatcher port wave). H21 uninstalled; H22 the only live target. |
| v5.24.0 | The H22 drop-harness, reconciled — a fresh drop-day blueprint arrived describing work that mostly already shipped; it was reconciled against reality (two gate-breaking conflicts caught before any write) rather than executed literally, and five genuinely-missing Phase-0 hardening gaps were built: a read-only mode guard, a new-family re-sweep spec, the scope fence extended to H22 rigging names, a theme-source seam, and the perception "before photo." No artist-facing behavior changed. |
| v5.23.0 | One Moneta · honest claims · the H22 blueprint harness — the docs realigned to the code (Moneta is the memory substrate), the test badge dropped to its real green-floor, the local-first security posture stated plainly, and the H22 gap-closure blueprint got a one-command orchestrator that stops at every human gate. A documentation-integrity + H22-prep release; no product code changed. |
| v5.22.0 | The honest envelope + evidence-based anchors + the drop-day runbook — receipts on both roads into Houdini (the audited /mcp bridge and the live panel path, recorded honestly, never faked); integrity flags now derived from runtime evidence instead of self-report (fidelity 1.0 = verified); composition validation extended to payload / inherit / specialize arcs; and the H22 drop compressed to one ordered, human-gated page. |
| v5.21.0 | Diagnostic truth + the self-protecting harness + the readiness verdict — the scene interrogated live (dirty-propagation / recook / time-dependence cataloged per context — the truth class no external LLM can hold), the harness that guards its own green (full-suite ratchet, posture-scoped red-driver, fix-is-real probes), and an honest READY (solo posture) verdict with the trade-offs named instead of hidden. |
| v5.20.0 | H22 drop-day machine + utility flywheel + panel v9/v9.1 — the API-delta probe (proven empty on H21, caught 15 phantom spellings in our own emitters), the self-improving probe→review→wire loop, and the five-engine panel: Claude · Gemini · NVIDIA Nemotron · Ollama · Custom, the author token, one CHAT surface where consent auto-surfaces (v9.1), bundled Space Grotesk/Mono, a token-only meter. |
| v5.19.0 | The build half landed — a validated proposal becomes real nodes under one undo group, with mid-build rollback. Plus the Solaris production-wiring correction (phantom per-shape lights purged, merge/sublayer strength rule live-probed). |
| v5.18.0 | Whole-graph validation — every proposed node + wire checked against the live scene before anything is built; the occupied-input guard halts rather than sever artist wiring. |
| v5.17.x | PDG cook-watcher fixed (phantom event-handler idiom replaced with the real one) · Solaris/USD parm names live-grounded — silently-no-op'd light writes now land · latency visibility — the LLM turn is ~95% of each step, Houdini ops run 1–70 ms; the audit fsync moved off the hot path · license split so GitHub detects pure MIT. |
| v5.16.0 | Multi-provider selector (first three engines) · prompt caching · one-call render-ready Solaris builds. |
✦ Install — 5 minutes
Artists: the steps below get you chatting — no command line beyond a copy-paste. Developers who want the editable install + test suite: docs/getting-started/installation.md.
Tested on Windows 11 + Houdini 22.0.368 — the only build currently live-tested here. (H21 code paths are retained and major-aware, but H21 is no longer installed on this machine.) macOS / Linux: same steps, different slashes.
%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#E8963B','primaryTextColor':'#1A1208','primaryBorderColor':'#9C5A10','lineColor':'#7A4310','secondaryColor':'#EEA958','tertiaryColor':'#F2BC77','edgeLabelBackground':'#F2BC77','clusterBkg':'#F2BC77','clusterBorder':'#9C5A10'}}}%%
flowchart LR
DL["1 · Download<br/>the SYNAPSE folder"]:::step --> REG["2 · Run the installer<br/>(once)"]:::step
REG --> KEY["3 · Add your API key<br/>to the .env"]:::step
KEY --> OPEN["4 · Restart Houdini,<br/>open the panel"]:::step
OPEN --> CHAT["Type 'make a box'<br/>→ it builds"]:::done
classDef step fill:#E8963B,stroke:#9C5A10,color:#1A1208
classDef done fill:#DE8425,stroke:#6B3A0C,color:#1A1208
1 · Get the files (~1 min) — green Code ▸ Download ZIP, unzip somewhere stable (e.g. C:\Users\<you>\SYNAPSE).
Prefer git? git clone https://github.com/JosephOIbrahim/Synapse.git
✅ You should see a
SYNAPSEfolder containingpython/,scripts/, andREADME.md.
2 · Tell Houdini about it (~1 min, once):
python scripts/install_synapse_package.py
The installer auto-detects your Houdini prefs directory and writes a package file pointing at this repo (--pref-dir overrides, --dry-run previews).
No Python on PATH? Use Houdini's: & "C:\Program Files\Side Effects Software\Houdini 22.0.368\bin\hython.exe" scripts/install_synapse_package.py (match your installed build/version.)
✅ You should see a success line ending in the wired
python/path — and no traceback.
2b · Check it took (~10 sec — optional, but it's the whole install on one screen):
python scripts/install_synapse_package.py --verify
Read-only — it writes nothing, anywhere. It re-checks each condition from state on disk, so it still works long after the install output scrolled away.
✅ You should see every row
PASSand a closingAll programmatic checks pass.If you see aFAILrow, it names the fix — an unwired pref dir means re-run step 2 without--dry-run; a missing key means finish step 3. The threeMANUALrows are the checks nothing outside Houdini can honestly make (the menu entry, "make a box", the Connect button). They're never counted as passing — you confirm those yourself in step 4.
3 · Add your Claude key (~2 min) — make one at console.anthropic.com (sk-ant-…), then put it in a .env at the repo root (gitignored, auto-loaded). This keeps the key scoped to SYNAPSE — it is not set as a system-wide ANTHROPIC_API_KEY, so it can't collide with or bill other Anthropic tools on your machine.
Other engines go in the same .env. Ollama needs no key (it's your local server), and Custom is configured right in the panel (base URL · model · key).
ANTHROPIC_API_KEY=sk-ant-...
GEMINI_API_KEY=AIza...
NVIDIA_API_KEY=nvapi-...
4 · Restart Houdini (~1 min) → New Pane Tab ▸ Synapse → type "make a box."
✅ You should see the Synapse entry in the New Pane Tab menu (title-case — scan for
Synapse, notSYNAPSE), and "make a box" create a real geo node you can Ctrl+Z.
That's the whole loop — start to chatting in ~5 minutes. Everything is an ordinary Houdini action — Ctrl+Z undoes it.
| Symptom | Likely cause | Fix |
|---|---|---|
Synapse isn't in the Pane Tab menu |
Houdini loads packages only at launch | Fully restart Houdini, then run python scripts/install_synapse_package.py --verify — it confirms from disk which pref dirs are wired, so you don't need the original install output. |
| "No API key" / won't connect | The key line is missing from the repo-root .env, or Houdini was already open when you added it |
Confirm the ANTHROPIC_API_KEY (and any GEMINI_API_KEY / NVIDIA_API_KEY) line in the .env at the repo root, then relaunch Houdini from scratch — the .env loads at startup. Fastest check: --verify (step 2b) reports the key as present or absent, and which source wins. To confirm it landed inside Houdini, in its Python Shell: from synapse.host import auth; import os; print(bool(os.environ.get('ANTHROPIC_API_KEY'))) → True. |
ModuleNotFoundError: No module named 'synapse' |
The package path wasn't wired, or Houdini wasn't restarted | Run --verify (step 2b) — the package file row shows whether a pref dir points at this repo's python/ directory. Fix, then restart Houdini. |
| Panel loads but says it can't reach Houdini | The bridge server isn't up — it never auto-starts | Click Connect in the panel footer strip (one click force-starts it; it then reads Bridge ✓). Only needed for external / MCP tools — ordinary chat runs in-process. |
✦ How it works — inside-out
Most AI-for-DCC tools run the agent in a separate process and reach in through a bridge — every call a round-trip, every tool a marshalling problem. SYNAPSE inverts that: the agent loop runs inside Houdini's own interpreter, dispatching tools as direct in-process calls against hou. The same pattern composes across the portfolio (a **Nu
No comments yet
Be the first to share your take.