A new infrastructure for Agentic Analog and Mixed-Signal Design. LLM Agents drive Cadence Virtuoso instances — locally or remotely — turning tedious handcrafting into automated design flows.
1. Deep Virtuoso Integration — Control across Schematic, Layout, Maestro, and Spectre.
- Flexible programming: execute inline SKILL, load
.ilfiles, or use Python APIs - Four design domains: schematic editing, layout generation, simulation setup (Maestro), and standalone Spectre with PSF parsing
2. Scalable Architecture — Multi-server, multi-session, built for distributed design clusters.
- Multi-profile SSH: connect to N design servers, each with independent tunnel
- Run parallel simulations across servers and accounts
- Verified across macOS, Windows, and Linux
3. AI-Native Design — Built for coding agents (Claude Code, Cursor, etc.) to drive Virtuoso.
- CLI-first:
virtuoso-bridge start/status/restart, no GUI needed - Ships with pre-defined agent skill files (
skills/) — the agent knows how to use the bridge immediately - Optimized for high-frequency agent interactions with persistent SSH tunnels
If you are an AI agent, read
AGENTS.mdfirst and follow its setup checklist.
| You want to... | Use this path | Needs |
|---|---|---|
| Drive Virtuoso on a remote EDA server | Remote mode | SSH access, running Virtuoso, load(...) in CIW |
| Drive Virtuoso on the same machine | Local mode | Running Virtuoso, VB_REMOTE_HOST=localhost |
| Run Spectre from netlists | Spectre simulator | spectre on PATH, or VB_CADENCE_CSHRC |
| Run reproducible IC optimization workflows | Optimizer skill + optional external workflow CLI | Spectre/OCEAN setup, requirement files |
| Let a coding agent operate Cadence | Agent skills | Link skills/ into your agent's skill directory |
Virtuoso SKILL execution and Spectre simulation are independent. You can run Spectre without the SKILL bridge, and you can use the SKILL bridge without Spectre.
Python entry points discover the nearest parent .env containing
VB_REMOTE_HOST or VB_LOCAL_PORT, then load it with override=True; this can
change a long-lived process from local to remote mode. Pin the intended file
before constructing a client when embedding the bridge:
from virtuoso_bridge.env import set_runtime_env_file
set_runtime_env_file("/path/to/virtuoso-bridge.env")# 0. Get the source
git clone https://github.com/Arcadia-1/virtuoso-bridge-lite.git
cd virtuoso-bridge-lite
# 1. Install in a virtual environment
uv venv .venv
source .venv/bin/activate
uv pip install -e .
# 2. Create ~/.virtuoso-bridge/.env
virtuoso-bridge init user@host [-J user@jump-host]
# Or: virtuoso-bridge init # empty template; edit VB_REMOTE_HOST yourself
# 3. Start and verify
virtuoso-bridge start # starts tunnel and prints the CIW load(...) line
virtuoso-bridge status # tunnel + Virtuoso daemon + Spectre availabilityOn Windows PowerShell, replace the activation line with
.\.venv\Scripts\Activate.ps1.
from virtuoso_bridge import VirtuosoClient
client = VirtuosoClient.from_env()
client.execute_skill("1+2") # VirtuosoResult(status=SUCCESS, output='3')Useful first commands after the bridge is up:
virtuoso-bridge windows # list all open Virtuoso windows
virtuoso-bridge screenshot # screenshot CIW to the user artifact directory
virtuoso-bridge export-visio MyLib MyCell -o MyCell.vsdx # Windows + Visio…or skip Python entirely — run SKILL straight from the shell:
# One-liner — full VirtuosoResult JSON on stdout
virtuoso-bridge eval 'getCurrentTime()'
# Multi-line SKILL via heredoc (auto-wrapped in progn; returns the last form)
virtuoso-bridge eval --stdin <<'EOF'
let((libs)
libs = mapcar(lambda((l) l~>name) ddGetLibList())
printf("found %d libraries\n" length(libs))
libs)
EOF
# Whole .il file — uploaded automatically in SSH mode
virtuoso-bridge load my_script.ilFor detailed setup (jump hosts, multi-profile, local mode), see AGENTS.md.
All commands take -p PROFILE / --env PATH to pick a non-default config; run virtuoso-bridge <cmd> --help for full flags.
| Command | What it does |
|---|---|
| Tunnel / lifecycle | |
init [user@host] [-J jump] |
Write a starter .env (no args = empty template) |
start [--bind-venv] |
Start SSH tunnel + deploy daemon; --bind-venv (with -p X) also binds the active virtualenv to profile X |
stop |
Stop the SSH tunnel |
restart |
Restart tunnel and refresh the deployed daemon setup |
status |
Tunnel + daemon health + Spectre availability |
license |
Check Spectre license availability |
| Profile binding | |
profile show |
Print the resolved profile, its source, and the active venv binding path |
profile bind PROFILE --venv |
Pin the active virtualenv to PROFILE (naked from_env() calls in that venv resolve to it) |
profile clear --venv |
Remove the venv binding |
| SKILL execution | |
load FILE.il |
Run a .il file in Virtuoso (uploads it in SSH mode). VS Code task–friendly; outputs VirtuosoResult JSON |
eval 'EXPR' / eval --stdin |
Run an inline SKILL expression; supports multi-statement via auto-wrapped progn(...) |
| Interaction / diagnostics | |
windows |
List all open Virtuoso windows (number + name) |
screenshot [ciw|current|N] [-o DIR|FILE] |
Capture a window; defaults to the user artifact screenshots directory |
dismiss-dialog |
X11 path: find and dismiss blocking GUI dialogs (saves you when SKILL channel deadlocks on a modal) |
list-windows [--json] |
X11 path: enumerate Virtuoso-related windows, including frame/child IDs and suggested modal actions |
dismiss-window WINDOW_ID [--action enter|escape|alt-y|alt-n] |
X11 path: send an explicit action to one window ID returned by list-windows |
snapshot [-o DIR] [--history H] |
Dump the focused Virtuoso window (maestro/schematic/...) — brief by default, full disk dump with -o |
| Export | |
export-visio LIB CELL -o OUT.vsdx |
Render a Virtuoso schematic to Microsoft Visio (Windows + pywin32) |
| SKILL Finder | |
skill-find <query> |
Search SKILL functions by name (fuzzy/prefix/suffix/exact/regex) |
skill-info <fn> |
Get detailed More Info docs for a SKILL function |
doc-search <query> |
Search installed Cadence documentation through the active bridge, or pass --doc-root for local/offline search |
Pull the currently-focused maestro session's setup + latest-run artifacts to a local folder:
virtuoso-bridge snapshot -o output # auto-picks newest history
virtuoso-bridge snapshot -o output --history Interactive.160 # pin a specific historyOutput tree (one example):
output/20260422_142137__MyLib__myTB/
├── maestro.sdb, active.state # raw Cadence files
├── state_from_sdb.xml, state_from_active_state.xml # filtered, high-signal
├── state_from_skill.txt # SKILL-probe setup summary
└── Interactive.N/
├── Interactive.N.{log,rdb,msg.db} # run-level (rdb = SQLite)
└── <pt>/<tb>/
├── netlist/ → netlist, input.scs, qpInformation.ils, paramInfo.ils
└── psf/ → spectre.out, logFile, dcOp.dc, *.ac, *.tran, ...
Per-point netlist/ keeps only the 4 files that actually describe the design (main SPICE netlist, testbench top level, FOM definitions, corner label). Psf keeps stdout + logs + non-binary analysis results. The full rule set — including what's commented out and why — lives in src/virtuoso_bridge/virtuoso/maestro/snapshot_filter.yaml; edit the YAML (uncomment / comment lines) to add or drop files, no code change needed. Binary waveforms (*.raw, wavedb/) are never pulled — read them through reader.runs.read_results instead.
The skills/ directory ships Claude Code skills
(virtuoso, spectre, netlist, optimizer). They are not symlinked into the repo's
.claude/skills/ on purpose — repo-tracked symlinks break on Windows and hardcode
one user's absolute paths. Instead, each user links them into their own
~/.claude/skills/ once after cloning:
# macOS / Linux
mkdir -p ~/.claude/skills
ln -s "$(pwd)/skills/virtuoso" ~/.claude/skills/virtuoso
ln -s "$(pwd)/skills/spectre" ~/.claude/skills/spectre
ln -s "$(pwd)/skills/netlist" ~/.claude/skills/netlist
ln -s "$(pwd)/skills/optimizer" ~/.claude/skills/optimizer# Windows (PowerShell, Developer Mode or elevated shell)
New-Item -ItemType Directory -Force "$env:USERPROFILE\.claude\skills" | Out-Null
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.claude\skills\virtuoso" -Target "$PWD\skills\virtuoso"
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.claude\skills\spectre" -Target "$PWD\skills\spectre"
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.claude\skills\netlist" -Target "$PWD\skills\netlist"
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.claude\skills\optimizer" -Target "$PWD\skills\optimizer"Cursor and other agents that load skills from a user-level directory follow the
same pattern — point their skills path at skills/ in this repo.
- VirtuosoClient — pure TCP SKILL client. Sends SKILL as JSON, gets results. No SSH awareness.
- SpectreSimulator — runs standalone Spectre simulations locally or through SSH, then parses PSF ASCII results into Python data.
- SSHClient — maintains a persistent ControlMaster connection for TCP port-forwarding, remote shell commands, and file transfer. Optional — bypassed in local mode.
Fully decoupled: VirtuosoClient works with any TCP endpoint — SSH tunnel, VPN, direct LAN, or local. Multiple connection profiles are supported, each managing an independent tunnel to a separate design server.
Want to understand the raw mechanism? Start with
src/virtuoso_bridge/virtuoso/basic/resources/ramic_bridge.ilandsrc/virtuoso_bridge/virtuoso/basic/bridge.py.
Want to use Virtuoso locally without SSH? See Local mode in AGENTS.md.
| Feature | virtuoso-bridge-lite | skillbridge |
|---|---|---|
| Core mechanism | ipcBeginProcess + evalstring |
ipcBeginProcess + evalstring |
| Local mode | Yes | Yes |
| Remote execution | SSH tunnel, jump host, auto-reconnect | Not supported |
| Calling style | String-based: execute_skill("dbOpenCellViewByType(...)") |
Pythonic mapping: ws.db.open_cell_view_by_type(...) |
| Load .il files | client.load_il() |
Not supported |
| Layout / schematic API | client.layout.edit() context manager |
Raw SKILL only |
| Spectre simulation | Built-in runner + PSF parser | Not supported |
| AI agent support | Skill files, CLI-first, command logging | Not designed for agents |
| Python ↔ SKILL types | String-based | Auto bidirectional mapping |
| IDE tab completion | No (not needed by agents) | Yes (Jupyter, PyCharm stubs) |
In short: Both projects are built on the same Cadence SKILL IPC facility, using the same core mechanism: ipcBeginProcess + evalstring + ipcWriteProcess. Here are the core lines from each:
virtuoso-bridge-lite — src/virtuoso_bridge/virtuoso/basic/resources/ramic_bridge.il
RBIpc = ipcBeginProcess(
sprintf(nil "%s %L %L %L" RBPython RBDPath host RBPort)
"" 'RBIpcDataHandler 'RBIpcErrHandler 'RBIpcFinishHandler "")
procedure(RBIpcDataHandler(ipcId data)
if(errset(result = evalstring(data)) then
ipcWriteProcess(ipcId sprintf(nil "%c%L%c" 2 result 30))
else
ipcWriteProcess(ipcId sprintf(nil "%c%L%c" 21 errset.errset 30))
)
)
skillbridge — skillbridge/server/python_server.il
pyStartServer.ipc = ipcBeginProcess(
executableWithArgs "" '__pyOnData '__pyOnError '__pyOnFinish pyStartServer.logName)
defun(__pyOnData (id data)
foreach(line parseString(data "\n")
capturedWarning = __pyCaptureWarnings(errset(result=evalstring(line)))
ipcWriteProcess(id lsprintf("success %L\n" result))
)
)
The divergence is in what's built on top: skillbridge stays thin — a Pythonic RPC client for interactive local use. virtuoso-bridge-lite adds SSH remote access, high-level layout/schematic APIs, Spectre simulation, and an AI-agent-ready harness.
If you use virtuoso-bridge in academic work, please cite:
@article{zhang2025virtuosobridge,
title = {Virtuoso-Bridge: An Agent-Native Bridge for Remote Analog and Mixed-Signal Design Automation},
author = {Zhang, Zhishuai and Li, Xintian and Sun, Nan and Jie, Lu},
year = {2025}
}- Zhishuai Zhang — Tsinghua University
- Xintian Li — Tsinghua University
- Nan Sun — Tsinghua University
- Lu Jie — Tsinghua University
