Skip to main content

AI-Houdini Bridge - WebSocket communication, persistent project memory, and foundation utilities (determinism, audit, gates)

Project description

Synapse

AI-Houdini Bridge with Persistent Project Memory

Version Python License Tests Protocol


What is Synapse?

Synapse lets an AI see, touch, and remember everything in your Houdini scene — it can read parameters, create and wire up nodes, run Python and VEX code, light and render with Karma, and manipulate USD stages, all through a real-time conversation. On top of that, it keeps a persistent project memory that remembers your decisions, tracks what happened across sessions, and gives the AI full context about your project every time you reconnect.

Built as a standalone package with zero required dependencies.

Key Features

  • 43 MCP Tools -- Full Houdini control from Claude: nodes, parameters, USD, materials, lighting, rendering, viewport capture
  • Persistent Memory -- Project memory stored alongside your HIP file with search, decisions, and context summaries
  • Living Memory -- Evolving per-project and per-scene markdown journals that grow with your work
  • Wire Protocol -- Typed commands over WebSocket with parameter aliasing and deterministic queuing
  • Agentic Execution -- prepare / propose / execute / learn loop with automatic risk classification
  • Human-in-the-Loop Gates -- Four levels (INFORM, REVIEW, APPROVE, CRITICAL) with batch approval
  • VEX Execution -- Run VEX wrangles directly from conversation
  • Production Resilience -- Rate limiter, circuit breaker, port failover, watchdog, backpressure
  • Viewport + Render Capture -- AI can see what you see via flipbook and Karma renders
  • RAG-Powered Routing -- Knowledge lookup from Houdini documentation (21 built-in workflow recipes)
  • Determinism -- Fixed-precision rounding, content-based IDs, Kahan summation ([He2025] inspired)
  • Houdini Optional -- All 874 tests run without Houdini; core library has zero required dependencies


Installation

There are two paths depending on how you want to use Synapse:

Path You want to... Time
A. Claude + Houdini Talk to Houdini through Claude Desktop or Claude Code ~5 min
B. Developer Hack on Synapse itself, run tests, add features ~5 min

Most artists want Path A. If you just want to try it, start there.



Path A: Connect Claude to Houdini

This is the most common setup. You'll end up with Claude talking directly to your Houdini scene.


Step 1 — Download Synapse

Open a terminal (Command Prompt, PowerShell, or Terminal) and run:

git clone https://github.com/JosephOIbrahim/Synapse.git

This creates a Synapse/ folder wherever you ran the command.

Don't have git? Download the ZIP from the green "Code" button on the GitHub page and unzip it.


Step 2 — Install the Python package

cd Synapse
pip install -e ".[websocket,mcp]"

This installs Synapse plus the two things it needs to work:

  • websocket — lets Synapse talk to Houdini
  • mcp — lets Claude talk to Synapse

Tip: If pip isn't recognized, try python -m pip install -e ".[websocket,mcp]" instead.


Step 3 — Start the server inside Houdini

Open Houdini, then open the Python Shell (Windows > Python Shell) and paste:

import sys
sys.path.insert(0, r"C:\path\to\Synapse\python")  # <-- change this to YOUR path

from synapse.server.websocket import SynapseServer
server = SynapseServer(port=9999)
server.start()

You should see a message confirming the server started on port 9999.

Important: Replace C:\path\to\Synapse\python with the actual path to the python/ folder inside your cloned Synapse directory.


Step 4 — Tell Claude about Synapse

Pick whichever Claude app you use:


Claude Code (terminal)

If you open Claude Code from inside the Synapse folder, it auto-detects the tools (via .mcp.json). Done.

To make it available from any folder:

claude mcp add synapse -- python /path/to/Synapse/mcp_server.py

Claude Desktop (app)

Open your config file:

  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

Add this inside "mcpServers":

{
  "mcpServers": {
    "synapse": {
      "command": "python",
      "args": ["C:/path/to/Synapse/mcp_server.py"]
    }
  }
}

Restart Claude Desktop. You'll see 43 new tools in the tool picker.


Step 5 — Try it

With Houdini open and the server running, say something to Claude like:

"What's in my scene right now?"

or

"Create a sphere and a distant light, then capture the viewport so I can see it."

Claude will use Synapse to read your scene, create nodes, adjust parameters, and show you the result. Everything happens in real time.



Path B: Developer Setup

For contributing, running tests, or building on top of Synapse.


Clone and install with all extras

git clone https://github.com/JosephOIbrahim/Synapse.git
cd Synapse
pip install -e ".[dev,websocket,mcp,routing,encryption]"
Extra What it adds
dev pytest, coverage, mypy
websocket WebSocket server for Houdini bridge
mcp MCP server for Claude integration
routing LLM-powered routing tier (Anthropic API)
encryption Fernet encryption for data at rest
memory Cross-process file locking for scene memory

Run the tests

python -m pytest tests/ -v

All 874 tests run without Houdini. No license needed.


Type checking

python -m mypy python/synapse/ --config-file pyproject.toml

Clean: 0 errors on 58 source files.


Houdini panel setup (optional)

If you want the Qt panel inside Houdini, symlink the panel definition:

# Windows (run as admin)
mklink "%USERPROFILE%\Documents\houdini20.5\python_panels\synapse.pypanel" "%CD%\houdini\python_panels\synapse.pypanel"

# macOS / Linux
ln -s "$(pwd)/houdini/python_panels/synapse.pypanel" ~/houdini20.5/python_panels/synapse.pypanel

Or add to your houdini.env:

HOUDINI_PATH = "/path/to/Synapse/houdini;&"

Then in Houdini: Windows > Python Panel > Synapse.



Encryption (Optional)

Synapse supports optional Fernet (AES-128-CBC + HMAC-SHA256) encryption for all data at rest — memory, audit logs, gate proposals, and markdown files.

pip install -e ".[encryption]"

Key management (priority order):

  1. SYNAPSE_ENCRYPTION_KEY environment variable (base64-encoded Fernet key)
  2. ~/.synapse/encryption.key file (auto-created with 0600 permissions)
  3. Auto-generated on first use

Encryption is transparent: existing plaintext .synapse/ directories load without migration. New writes are encrypted; reads auto-detect encrypted vs plaintext content.



Troubleshooting

Problem Fix
pip not found Use python -m pip instead of bare pip
git not found Download the ZIP from GitHub instead, or install Git for Windows
Server won't start Make sure nothing else is using port 9999. You can change it: SynapseServer(port=9998)
Claude can't connect Check that the server is running in Houdini before talking to Claude
ModuleNotFoundError Make sure you ran pip install -e ".[websocket,mcp]" from inside the Synapse folder
Tools don't appear in Claude Desktop Restart Claude Desktop after editing the config file
Wrong Python version Synapse needs Python 3.9+. Run python --version to check

Architecture

+---------------------------------------------------------------+
|                         Synapse v5.2.0                        |
+---------------------------------------------------------------+
|                                                               |
|  +-- UI Layer (Qt) ----------------------------------------+ |
|  |  SynapsePanel > Connection | Context | Decisions |       | |
|  |                  Activity  | Search                      | |
|  +----------------------------------------------------------+ |
|                                                               |
|  +-- Agent Layer -------------------------------------------+ |
|  |  AgentExecutor: prepare -> propose -> execute -> learn   | |
|  |  AgentTask / AgentPlan / AgentStep / OutcomeTracker      | |
|  +----------------------------------------------------------+ |
|                                                               |
|  +-- Session Layer -----------------------------------------+ |
|  |  SynapseBridge  |  SynapseSession  |  SessionSummary     | |
|  +----------------------------------------------------------+ |
|                                                               |
|  +-- Memory Layer ------------------------------------------+ |
|  |  SynapseMemory  |  MemoryStore  |  MarkdownSync          | |
|  |  Memory / MemoryType / MemoryTier / MemoryQuery          | |
|  +----------------------------------------------------------+ |
|                                                               |
|  +-- Server Layer ------------------------------------------+ |
|  |  SynapseServer (WebSocket)  |  CommandHandlerRegistry    | |
|  |  RateLimiter | CircuitBreaker | PortManager | Watchdog   | |
|  |  BackpressureController | HealthMonitor                  | |
|  +----------------------------------------------------------+ |
|                                                               |
|  +-- Core Layer (Foundation) -------------------------------+ |
|  |  protocol.py   Wire format, CommandType, aliases         | |
|  |  queue.py      DeterministicCommandQueue                 | |
|  |  determinism.py Fixed-precision, content IDs, seeded RNG | |
|  |  audit.py      Hash-chain append-only log                | |
|  |  gates.py      INFORM / REVIEW / APPROVE / CRITICAL      | |
|  +----------------------------------------------------------+ |
|                                                               |
+---------------------------------------------------------------+

Core provides the wire format, determinism primitives, tamper-evident audit, and human gates. Memory persists decisions, context, and actions to $HIP/.synapse/ with markdown export. Server runs the WebSocket bridge with production resilience (rate limiting, circuit breaker, port failover, watchdog, backpressure). Agent orchestrates multi-step plans through the gate system with outcome-based learning. Session tracks lifecycle and generates summaries. UI provides the Houdini Qt panel.

Usage

Memory

from synapse import SynapseMemory, MemoryType

memory = SynapseMemory()

# Add typed memories
memory.note("Switched to Arnold renderer", tags=["render"])
memory.action("Created key light", node_paths=["/obj/key_light"])
memory.decision(
    decision="Use ACES color space",
    reasoning="Studio standard for color management",
    alternatives=["sRGB", "Linear"],
)

# Search
results = memory.search("color space", limit=10)

# Get all decisions
decisions = memory.get_decisions()

# Context summary (useful for feeding to AI)
summary = memory.get_context_summary()

# Persist to disk
memory.save()

Agent Execution

The flagship feature. Agents follow a four-phase loop: prepare (gather context from memory), propose (define steps, route through gates), execute (run commands or dry-run), learn (record outcomes as feedback memories).

from synapse import AgentExecutor, AgentStep, SynapseMemory, HumanGate

# No command_fn = dry-run mode (no Houdini needed)
executor = AgentExecutor(
    memory=SynapseMemory(),
    gate=HumanGate.get_instance(),
)

# Phase 1: Prepare (searches memory for relevant context)
task = executor.prepare(
    goal="Set up three-point lighting for shot_010",
    sequence_id="shot_010",
    category="lighting",
    agent_id="claude",
)

# Phase 2: Propose (define steps, auto-classify gate levels)
plan = executor.propose(
    task=task,
    steps=[
        AgentStep(
            step_id="",
            action="create_node",        # Auto-classified: REVIEW
            description="Create key light",
            payload={"type": "arealight", "name": "key_light"},
            gate_level=None,
            reasoning="Primary illumination source",
            confidence=0.9,
        ),
        AgentStep(
            step_id="",
            action="set_parm",            # Auto-classified: REVIEW
            description="Set intensity to 1000",
            payload={"node": "/obj/key_light", "parm": "light_intensity", "value": 1000.0},
            gate_level=None,
            reasoning="Standard key light intensity",
            confidence=0.85,
        ),
    ],
    reasoning="Classic three-point lighting setup",
)

# Phase 3: Execute
if plan.status.value == "approved":
    completed = executor.execute(plan)
    print(completed.to_summary())

# Phase 4: Learn
executor.record_outcome(plan, success=True, feedback="Client approved")

Human-in-the-Loop Gates

Every agent action is classified by risk level. Reads auto-approve; creates batch for review; deletes require explicit approval; code execution requires full stop.

from synapse import HumanGate
from synapse.core.audit import AuditCategory
from synapse.core.gates import GateLevel, GateDecision

gate = HumanGate.get_instance()

# Agent proposes a change
proposal = gate.propose(
    operation="delete_node",
    description="Remove unused bounce light",
    sequence_id="shot_010",
    category=AuditCategory.LIGHTING,
    level=GateLevel.APPROVE,          # Deletion = explicit approval
    proposed_changes={"node": "/obj/bounce_light"},
    reasoning="Light contributes <1% to final render",
    confidence=0.7,
    agent_id="claude",
)

# Human decides
gate.decide(
    proposal_id=proposal.proposal_id,
    decision=GateDecision.APPROVED,
    user_id="artist_joe",
    notes="Confirmed, bounce light was a holdover from previous setup",
)

# Or batch approve an entire sequence
gate.approve_all("shot_010", user_id="artist_joe")

Gate levels and auto-classification:

Level Behavior Example commands
INFORM Auto-approve, log only get_parm, get_scene_info
REVIEW Batch for later review create_node, set_parm
APPROVE Block until approved delete_node, connect_nodes
CRITICAL Full stop, confirm twice execute_python, execute_vex

Determinism

Fixed-precision arithmetic and content-based identifiers ensure reproducible workflows.

from synapse.core.determinism import (
    round_float,
    deterministic_uuid,
    DeterministicRandom,
    deterministic,
)

# Fixed-precision rounding (Decimal ROUND_HALF_UP)
value = 0.1 + 0.2               # 0.30000000000000004
rounded = round_float(value)     # 0.3

# Content-based UUIDs (same input = same ID, always)
id_a = deterministic_uuid("shot_010:key_light")
id_b = deterministic_uuid("shot_010:key_light")
assert id_a == id_b

# Seeded RNG (reproducible sequences)
rng = DeterministicRandom(seed=42)
rng.uniform(0.0, 1.0)   # Same result every run
rng.shuffle([1, 2, 3])  # Same order every run

# Decorator: auto-rounds float arguments
@deterministic
def place_light(x: float, y: float, z: float):
    return (x, y, z)

Resilience

Production-grade stability for long-running Houdini sessions.

from synapse.server.resilience import (
    RateLimiter,
    CircuitBreaker,
    CircuitBreakerConfig,
    Watchdog,
    BackpressureController,
    HealthMonitor,
)

# Token-bucket rate limiter (global + per-client)
limiter = RateLimiter(tokens_per_second=50.0, bucket_size=100)
allowed, info = limiter.acquire(client_id="claude")

# Circuit breaker (trips on service errors, ignores user errors)
breaker = CircuitBreaker("houdini", CircuitBreakerConfig(
    failure_threshold=5,
    timeout_seconds=60.0,
))
result = breaker.call(some_houdini_function, arg1, arg2)

# Watchdog (detects main thread freezes)
dog = Watchdog(timeout_seconds=30.0)
dog.start()
dog.pet()   # Call periodically from main thread

# Backpressure (NORMAL -> ELEVATED -> HIGH -> CRITICAL)
bp = BackpressureController()
bp.report_metric(queue_size=50, processing_time=0.2)
should_throttle, details = bp.should_throttle()

# Aggregate health
monitor = HealthMonitor()
monitor.update("websocket", healthy=True)
monitor.update("houdini", healthy=True)
report = monitor.get_report()

Audit Trail

Tamper-evident, append-only logging with cryptographic hash chain.

from synapse.core.audit import audit_log, AuditLevel, AuditCategory

log = audit_log()

# Log an agent action
log.log_agent_action(
    operation="create_light",
    message="Created key light at /obj/key_light",
    agent_id="claude",
    category=AuditCategory.LIGHTING,
    sequence_id="shot_010",
)

# Log a human decision
log.log_human_decision(
    operation="approve_plan",
    message="Approved lighting setup",
    user_id="artist_joe",
    category=AuditCategory.GATE,
)

# Query entries
entries = log.get_entries(category=AuditCategory.LIGHTING, limit=20)

# Verify chain integrity (detect tampering)
valid, failed_at = log.verify_chain()
assert valid, f"Chain broken at entry {failed_at}"

Wire Protocol

Default endpoint: ws://localhost:9999 | Protocol version: 4.0.0

Commands are JSON messages with type, id, payload, sequence, and timestamp fields.

Category Commands
Node create_node, delete_node, modify_node, connect_nodes
Parameters get_parm, set_parm
Scene get_scene_info, get_selection, set_selection
Execution execute_python, execute_vex
USD/Solaris create_usd_prim, modify_usd_prim, get_stage_info, set_usd_attribute, get_usd_attribute
Memory context, search, add_memory, decide, recall
Utility ping, get_health, get_help, heartbeat, backpressure

Parameter names are resolved through an alias system (38+ mappings). For example, node, path, and node_path all resolve to the canonical node parameter.

Claude Integration (MCP)

Synapse includes an MCP server that bridges Claude to Houdini with 43 tools. See Installation > Path A for setup steps.

Claude  <--[stdio/JSON-RPC]-->  mcp_server.py  <--[WebSocket]-->  Synapse (Houdini)

Available MCP Tools (43)

Category Tools
System synapse_ping, synapse_health
Scene houdini_scene_info, houdini_get_selection
Nodes houdini_create_node, houdini_delete_node, houdini_connect_nodes
Parameters houdini_get_parm, houdini_set_parm, houdini_set_keyframe
Execution houdini_execute_python, houdini_execute_vex
USD / Solaris houdini_stage_info, houdini_get_usd_attribute, houdini_set_usd_attribute, houdini_create_usd_prim, houdini_modify_usd_prim, houdini_reference_usd
Materials houdini_create_material, houdini_assign_material, houdini_read_material
Rendering houdini_render, houdini_render_settings, houdini_wedge, houdini_capture_viewport
Introspection synapse_inspect_selection, synapse_inspect_scene, synapse_inspect_node
Memory synapse_context, synapse_search, synapse_recall, synapse_decide, synapse_add_memory
Knowledge synapse_knowledge_lookup, synapse_list_recipes
Routing synapse_router_stats, synapse_metrics
Batch synapse_batch

Configuration

Environment Variable Default Description
SYNAPSE_PORT 9999 WebSocket port to connect to

Testing

# All 874 tests (no Houdini required)
python -m pytest tests/ -v

# Individual test modules
python -m pytest tests/test_core.py -v        # Determinism, audit, gates
python -m pytest tests/test_routing.py -v     # Routing cascade (323 tests)
python -m pytest tests/test_agent.py -v       # Agent protocol, executor, learning
python -m pytest tests/test_resilience.py -v  # Rate limiter, circuit breaker, watchdog
python -m pytest tests/test_render.py -v      # Karma/Mantra pipeline
python -m pytest tests/test_materials.py -v   # Material tools

# With coverage
python -m pytest tests/ --cov=synapse --cov-report=term-missing

All tests import modules directly and run without a Houdini license or environment.

Live Tests (Inside Houdini)

Some features (viewport capture, hwebserver transport) require a graphical Houdini session. Run these from the Houdini Python Shell:

# Viewport capture test (creates temp scene, captures, verifies, cleans up)
import runpy; runpy.run_path("tests/test_live_capture.py")

# hwebserver integration test
import runpy; runpy.run_path("tests/test_hwebserver_integration.py")

Project Structure

Synapse/
├── pyproject.toml
├── LICENSE
├── CLAUDE.md
├── mcp_server.py                       # MCP server (Claude Code / Desktop bridge)
├── .mcp.json                            # Claude Code project-level MCP config
├── houdini/
│   └── python_panels/
│       └── synapse.pypanel          # Houdini Qt panel definition
├── python/synapse/
│   ├── __init__.py                  # Public API surface
│   ├── core/
│   │   ├── protocol.py              # CommandType, SynapseCommand/Response
│   │   ├── queue.py                 # DeterministicCommandQueue
│   │   ├── aliases.py               # Parameter name resolution (38+ aliases)
│   │   ├── determinism.py           # Fixed-precision, content IDs, seeded RNG
│   │   ├── audit.py                 # Hash-chain append-only audit log
│   │   └── gates.py                 # Human-in-the-loop gate system
│   ├── memory/
│   │   ├── models.py                # Memory, MemoryType, MemoryTier, MemoryQuery
│   │   ├── store.py                 # SynapseMemory high-level API
│   │   ├── context.py               # ShotContext helpers
│   │   └── markdown.py              # MarkdownSync (human-readable export)
│   ├── routing/
│   │   ├── __init__.py              # Public routing API
│   │   ├── router.py                # TieredRouter (Cache→Recipe→Regex→Knowledge→LLM→Agent)
│   │   ├── parser.py                # CommandParser (regex patterns, first-match-wins)
│   │   ├── knowledge.py             # KnowledgeIndex (inverted keyword search from RAG)
│   │   ├── recipes.py               # RecipeRegistry (multi-step command sequences)
│   │   └── cache.py                 # ResponseCache (deterministic LRU with TTL)
│   ├── agent/
│   │   ├── protocol.py              # AgentTask, AgentPlan, AgentStep
│   │   ├── executor.py              # prepare -> propose -> execute -> learn
│   │   └── learning.py              # OutcomeTracker (feedback memories)
│   ├── server/
│   │   ├── websocket.py             # SynapseServer (WebSocket)
│   │   ├── handlers.py              # CommandHandlerRegistry
│   │   └── resilience.py            # RateLimiter, CircuitBreaker, Watchdog, ...
│   ├── session/
│   │   ├── tracker.py               # SynapseBridge, SynapseSession
│   │   └── summary.py               # Session summary generation
│   └── ui/
│       ├── panel.py                 # SynapsePanel (Qt)
│       └── tabs/                    # Connection, Context, Decisions, Activity, Search
└── tests/
    ├── test_core.py                 # Foundation layer tests
    ├── test_agent.py                # Agent layer tests
    ├── test_resilience.py           # Resilience layer tests
    ├── test_crypto.py               # Encryption layer tests
    ├── test_routing.py              # Routing engine tests (323 tests)
    ├── test_live_capture.py         # Viewport capture (run inside Houdini)
    └── test_hwebserver_integration.py # hwebserver transport (run inside Houdini)

Status

Synapse is under active development. All layers are well-tested (874 unit tests, mypy clean on 58 source files). The WebSocket server and viewport capture have been validated in single-user VFX workflows. Use in production at your own discretion.

Determinism Reference

Synapse's determinism primitives (round_float, kahan_sum, deterministic_uuid, @deterministic decorator) are inspired by [He2025] — "Defeating Nondeterminism in LLM Inference" by Horace He, Thinking Machines Lab. The key insight: batch invariance failure (not just floating-point non-associativity) is the primary source of nondeterminism. Synapse applies this at the application layer: fixed-precision rounding, content-based IDs, and Kahan compensated summation ensure reproducible state across sessions.

Related Projects

  • Orchestra -- Cognitive orchestration framework (v7.1.0, 1,500+ tests). Synapse is the Houdini bridge; Orchestra is the cognitive engine.
  • Cognitive Substrate -- Theoretical foundation for deterministic state composition.

Patent Notice

Certain methods and systems implemented in this software are the subject of a pending patent application. "Patent Pending" applies to, but is not limited to:

  • Tiered cognitive routing cascade with confidence-based tier forwarding
  • Persistent memory tier architecture with cross-tier linking
  • Deterministic state composition using priority-ordered resolution semantics
  • Agentic execution loop with gate-integrated outcome learning

Use of this software under the MIT License does not grant any rights under the patent application(s). See LICENSE for details.

License

MIT License. Copyright (c) 2025-2026 Joe Ibrahim.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

synapse_houdini-5.2.0.tar.gz (262.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

synapse_houdini-5.2.0-py3-none-any.whl (188.3 kB view details)

Uploaded Python 3

File details

Details for the file synapse_houdini-5.2.0.tar.gz.

File metadata

  • Download URL: synapse_houdini-5.2.0.tar.gz
  • Upload date:
  • Size: 262.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for synapse_houdini-5.2.0.tar.gz
Algorithm Hash digest
SHA256 8620f319e12a7653fa2f983f6d167f1a6f59f174214071a8b1b14c307f573383
MD5 e48f9edfefa7cbfdbb40835d2eee5b72
BLAKE2b-256 b2b667ec90ab73e420119489134f2f9b9f29bf55d506bcddc0b8c63275689d59

See more details on using hashes here.

File details

Details for the file synapse_houdini-5.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for synapse_houdini-5.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 68f01850999555d640cac8d088179156e4fb99039996af27335b25a0a4bbef2d
MD5 3a0a86a077f0ee75c00170d8601fcb45
BLAKE2b-256 8d2e25cb7abae196e736af852ec15457e3c5f7b9fed7a722308a7619e84956ca

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page