Control remote Cadence Virtuoso from any machine over SSH. No VNC, no X11. Python + SSH + AI agents.
Send any SKILL command to a running Virtuoso and get results back as Python dicts.
Python API for creating, modifying, and reading cellviews. Context managers handle open/save.
Upload netlists, run simulations remotely, parse PSF results — all from Python.
Automated parameter tuning via Spectre-in-the-loop. TuRBO, scipy, or any optimizer.

pip install -e .
virtuoso-bridge init # generates .env
# edit .env → set VB_REMOTE_HOST=my-server
virtuoso-bridge start
from virtuoso_bridge import VirtuosoClient
client = VirtuosoClient.from_env()
result = client.execute_skill("1+2")
print(result) # {'ok': True, 'result': {'output': '3', ...}}
| Method | Description |
|---|---|
execute_skill(code) | Run any SKILL expression, return result dict |
load_il(path) | Upload & load a .il file in Virtuoso |
execute_operations(cmds) | Run a batch of SKILL commands |
get_current_design() | Returns (lib, cell, view) of active cellview |
open_window(lib, cell) | Open a cellview in Virtuoso GUI |
save_current_cellview() | Save the active cellview |
upload_file(local, remote) | Upload a file to the remote machine |
download_file(remote, local) | Download a file from the remote machine |
run_shell_command(cmd) | Run a shell command on the remote host |
test_connection() | Ping the daemon to check connectivity |
with client.layout.edit("myLib", "myCell") as layout:
layout.add_rect("M1", "drawing", (0, 0, 1, 0.5))
layout.add_path("M2", "drawing", [(0,0),(1,0)], width=0.1)
layout.add_label("M1", "pin", (0.5, 0.25), "VDD")
layout.add_instance("tsmcN28", "nch_ulvt_mac", (0,0), "M0")
layout.add_via("M1_M2", (0.5, 0.25))
layout.add_polygon("M3", "drawing", [(0,0),(1,0),(1,1)])
shapes = layout.get_shapes()
with client.schematic.edit("myLib", "myCell") as sch:
sch.add_instance("analogLib", "vdc", (0,0), "V0", params={"vdc": "0.9"})
sch.add_wire([(0, 0), (0, 0.5)])
sch.add_pin("VDD", "inputOutput", (0, 1.0))
from virtuoso_bridge.spectre.runner import SpectreSimulator
sim = SpectreSimulator.from_env(work_dir="./output")
result = sim.run_simulation("tb_inv.scs", {})
print(result.status) # ExecutionStatus.SUCCESS
print(result.data.keys()) # ['time', 'VOUT', 'VIN', ...]
print(result.data["VOUT"][:5]) # first 5 voltage samples
from virtuoso_bridge import SSHClient, VirtuosoClient
# Create tunnel independently
tunnel = SSHClient.from_env()
tunnel.warm()
# Create bridge from tunnel
bridge = VirtuosoClient.from_tunnel(tunnel)
bridge.execute_skill("1+2")
# Or local mode — no tunnel needed
bridge = VirtuosoClient.local(port=65432)