| name | skill-exec |
| description | Execute SKILL code on Virtuoso. Use when running SKILL expressions, querying cellview data, listing libraries/cells, or interacting with Virtuoso programmatically. |
| argument-hint | ["SKILL expression to run"] |
| allowed-tools | Bash(vcli *) Bash(virtuoso *) |
Execute SKILL Code on Virtuoso
Run SKILL expressions via vcli skill exec and parse results.
Quick reference
vcli skill exec "1+2" --format json
vcli skill exec 'strcat("hello" " " "world")' --format json
vcli skill exec 'foreach(mapcar lib ddGetLibList() lib~>name)' --format json
vcli skill exec 'let((lib) lib=ddGetObj("myLib") foreach(mapcar c lib~>cells c~>name))' --format json
vcli skill exec 'let((cell) cell=ddGetObj("myLib" "myCell") foreach(mapcar v cell~>views v~>name))' --format json
vcli skill exec 'let((cv) cv=geGetEditCellView() list(cv~>libName cv~>cellName cv~>viewName))' --format json
vcli skill exec 'let((cv) cv=geGetEditCellView() length(cv~>instances))' --format json
vcli skill exec 'let((cv result n) cv=geGetEditCellView() result=nil n=0 foreach(net cv~>nets when(n<20 result=cons(net~>name result) n=n+1)) result)' --format json
vcli skill exec 'let((cv) cv=dbOpenCellViewByType("lib" "cell" "schematic" nil "r") sprintf(nil "inst=%d nets=%d" length(cv~>instances) length(cv~>nets)))' --format json
Multi-session usage
When multiple Virtuoso instances are running, specify the session explicitly:
vcli session list
vcli --session meowu-meow-38371 skill exec 'getCurrentTime()'
export VB_SESSION=meowu-meow-38371
vcli skill exec 'getCurrentTime()'
Connection failure recovery
⚠️ Gotcha: --session <id> bypasses auto-filtering. If Virtuoso restarts, the
session ID changes (new port → new ID). Explicitly specifying a dead session returns
connection_failed: Connection refused (exit 1) even though other sessions are alive.
Recovery pattern (observed signal: exit 1 on skill exec followed by session list):
vcli --session meowu-meow-32987 skill exec 'getCurrentTime()'
vcli session cleanup
vcli session list
vcli --session meowu-meow-38371 skill exec 'getCurrentTime()'
Multi-line input — skill eval --stdin
For snippets that span more than one line, or that contain characters painful to
shell-quote (double quotes, parens, dollar signs), pipe the SKILL through stdin
instead of stuffing it on the argv:
vcli skill exec '1+2' --format json
cat <<'EOF' | vcli skill eval --stdin --format json
let((x y)
x = 1 + 2
y = x * x
y
)
EOF
Both skill exec and skill eval go through the daemon, but they differ in two
ways that matter:
| skill exec | skill eval |
|---|
| Input | argv only (<code> positional) | argv OR --stdin |
| Multi-statement | daemon let((r) r=<code>) — single form only | wrapped in progn(\n<code>\n) — any number of forms |
Trailing ; comment | safe | safe (the \n) before ) terminates the line comment) |
| Return value | the daemon's r | the value of the last form inside progn |
Rule of thumb: use eval --stdin whenever your SKILL has more than one top-level
form, contains full-line comments, or defines a procedure then calls it.
⚠️ Gotcha — skill exec silently drops earlier forms. Inside the daemon's
let(((__vb_r <code>)) ...), f1() f2() parses as "apply the result of f1() to
the arguments of f2()" — only f2() runs. If you see printf(...) succeed but
the side effect you expected from the prior statement is missing, switch to
skill eval --stdin so the input is wrapped in progn(...).
CIW output vs return value
vcli skill exec (and eval) send the SKILL expression to Virtuoso for evaluation
and capture the return value back into the JSON output field. They do not
echo anything to the CIW window unless your expression does it itself with printf.
vcli skill exec '1+2' --format json
vcli skill exec 'let((v) v=1+2 printf("1+2 = %d\n" v) v)' --format json
When debugging a long expression, the printf(...) + final-form pattern is the
cleanest way to inspect intermediate state without leaving CIW trace breadcrumbs
that pollute later reads.
Attribution
The multi-line SKILL wrapping (progn(\n<code>\n)), --stdin input mode, and
the CIW output vs return-value distinction are adapted from
virtuoso-bridge-lite
(MIT, 2026-06) — specifically cli.py::cli_eval,
examples/01_virtuoso/basic/05_multiline_skill.py, and
examples/01_virtuoso/basic/00_ciw_output_vs_return.py.
Important notes
- Use
--format json for structured output (auto in pipe mode)
- Use
--timeout N for long-running operations (default 30s)
- SKILL strings use
", escape with \" inside bash single quotes
let blocks work for local variables; Ocean functions (simulator, design, run) must be at top level
- View names may not be standard
schematic — check with v~>name not v~>viewName
- Always wrap slot access in
let: let((cv) cv=geGetEditCellView() cv~>cellName) not geGetEditCellView()~>cellName — the latter crashes if no design is open