eda-agent
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| backend | No | Selects the backend, passed as --backend altium (the default), --backend kicad, or --backend easyeda. | altium |
| no-dashboard | No | Disables the dashboard, passed as the flag --no-dashboard. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| app_update_from_librariesA | Drive Tools > Update From Libraries, ECO included. THIS PRESSES BUTTONS IN THE GUI. Update From Libraries has no API: Altium documents it as a dialog, there is no process that launches it, and the operation ends in an Engineering Change Order that only a click can execute. So this matches windows belonging to the Altium process and presses named buttons on them. WHAT IT WILL DO AT THE END. The last steps press Validate
Changes and then EXECUTE CHANGES on the ECO. That applies every
pending change to the design and is not undoable through this
channel. Take WHAT IT CANNOT TELL YOU. While the wizard is open Altium's script engine is blocked, so the bridge cannot be asked anything, and an ECO's pending changes sit in a grid that exposes no text to Windows. The reply records the windows and buttons seen; it does NOT contain the change list. Read the Messages panel afterwards for that. NOTHING IS SCRIPTED. There is no list of expected dialogs. Each one that appears is read, classified, and answered by the ROLE of the buttons it offers, then the screen is read again. That is deliberate: a scripted version failed on live Altium because the editor legitimately shows dialogs no list contained, and waited for a change order that was never coming while an unlisted modal blocked the session. It STOPS rather than guessing when a dialog reports an error, asks a question it was not sent to answer, or offers no button whose meaning is recognised. RUN IT DRY FIRST, WHICH IS THE DEFAULT. A dry run reads the first dialog, reports what it is and what it would press, and presses nothing. LAUNCHING. Args:
target: Returns:
Dict with |
| app_set_dialog_controlA | Read or CHANGE a control inside whatever dialog is open. The other half of driving a dialog. Buttons are pressed by the dialog driver; this is for the checkboxes, radios and fields that decide what those buttons will DO. FIND BY LABEL, not position. EVERY CHANGE IS VERIFIED. The new state is read back, and a click that silently did nothing is reported as a failure rather than as success. That matters here more than anywhere: a caller that believes an option was applied will go on to press something irreversible. IT REFUSES RATHER THAN GUESSING when a control is DISABLED (Altium greys options that do not apply, and clicking one is at best a no-op), and when asked to switch a radio button OFF, which is not a thing a radio does. SETTING IS NOT A TOGGLE. Asking for a state the control is
already in reports Args: control_label: the control's visible label. checked: desired state for a checkbox. text: desired contents for an edit field. select_row: for a list, grid or tree, the row to select by name. Rows are matched by name for the same reason menu items are: positions shift and an index would pick the wrong one the first time the contents changed. dialog_title: substring to pick one dialog when several are open. Empty uses the first. list_only: change nothing, just report every control in the dialog with its role, state and whether it is enabled. Returns:
For a read, the control list. For a change, |
| app_click_menuA | Invoke ANY Altium menu command by path, by driving the menu. Use this when PATH BY NAME. IT NEEDS THE FOREGROUND. Altium has no Win32 menu and its
DevExpress bars expose no working accessible action, so the only
thing that opens them is real input: this brings Altium to the
front and briefly moves the pointer, putting it back afterwards.
Every other press in this package is addressed to a window
handle and depends on none of that, which is why this one is
gated behind THE MENU BAR IS PER EDITOR. With a board focused you get the PCB menus, with a schematic the schematic ones. Focus the matching document first, or the reply will tell you the item was not there and list what was. WHAT HAPPENS NEXT IS NOT THIS TOOL'S JOB. Many commands open a
dialog. Read it with Args:
menu_path: pipe-separated path, top level first.
may_steal_focus: required to actually click anything.
list_only: do not invoke. Reports the top-level menus
currently on screen, which is the way to find out what
this editor context offers.
expect_dialog: part of the title of the dialog the command
should open. Then Returns:
Dict with |
| app_list_open_dialogsA | What Altium has on screen, what it says, and if it is stuck. THE TOOL TO REACH FOR WHEN THE BRIDGE GOES QUIET. A silent
bridge looks identical whether Altium is showing a modal, busy
compiling, or dead. This answers it directly:
FOR EACH DIALOG you get the caption, the message text, every
button with its enabled state, and a
WHAT IT STILL CANNOT READ. Grids and owner-drawn lists hold
their content internally and expose no window text, so an ECO's
pending-change list is not readable. That is reported per dialog
as Reads only. Presses nothing. Returns:
Dict with |
| app_press_dialog_buttonA | Press ONE named button in an open Altium dialog. The missing primitive. Dialogs could be listed, read and their checkboxes set, but the only code that pressed anything was buried inside a single task-specific driver, so answering an arbitrary dialog meant writing a script. BY CAPTION, not position. Accelerator ampersands and a trailing ellipsis are ignored, so "Report Changes" finds "&Report Changes...". IT WORKS WHILE ALTIUM IS BLOCKED, because it addresses the button's window handle over Win32 and never touches the bridge. That is the whole point: when a modal has the scripting engine stuck, this is what gets it unstuck. IRREVERSIBLE PRESSES ARE GATED. A caption that commits a change
order or applies a wizard is refused unless
For a whole sequence rather than one press, use
Args: button_caption: the visible caption. dialog_title: substring picking one dialog when several are open. Empty uses the first. allow_irreversible: permit a committing press. Returns:
|
| app_drive_dialogsA | Answer dialogs reactively until none is left. The reactive driver, which existed but was reachable only through the one wizard tool that used it. It reads whatever is on screen, classifies it, decides a press from that, and repeats. There is no scripted sequence, so a dialog appearing in a different order, or not at all, is handled rather than breaking a plan. IT STOPS RATHER THAN GUESSING on a dialog it cannot classify,
and on anything that needs a human. THE TWO GATES ARE SEPARATE ON PURPOSE. Args: intent: "proceed" to carry the operation forward, or "cancel" to back out of whatever is open. allow_commit: permit the design-changing press. allow_confirm: permit answering a confirmation. dry_run: decide and report, press nothing. Default True. wait_first: seconds to wait for the first dialog, since a caller fires a command and then drives. budget: seconds before giving up on a wedged editor. Returns:
Every observation and decision, plus |
| app_run_ui_commandA | Invoke a menu command AND answer the dialogs it raises. The composite, and usually the one to reach for. Firing a menu command that opens a modal blocks Altium's scripting engine, so the two halves cannot be separate bridge calls: the second would never be answered. Both halves here are Win32, so they run in one call and the modal is no obstacle. Doing this by hand meant arming a watcher process before firing the command, which is not something a caller should have to assemble. THE GATES ARE THE DIALOG DRIVER'S. Args: menu_path: pipe-separated, for example "Tools|Annotation|Force Annotate All Schematics...". Discover paths with app_click_menu(list_only=True). allow_commit: permit a design-changing press. allow_confirm: permit answering confirmations. dry_run: invoke the command but press nothing. may_steal_focus: opening a menu needs real input. wait_first: seconds to wait for the first dialog. budget: seconds before giving up. expect_dialog: part of the title of the dialog the command should open. When a different dialog (or none) appears, the reply fails at the menu stage and nothing is driven. Returns:
|
| app_list_panelsA | Altium's dockable panels that are currently on screen. PANELS ARE NOT DIALOGS and were unreachable until now. A dialog
is a top-level window; a docked panel is a child of the main
frame, so Args: offered_too: also read what View > Panels lists, which is what COULD be opened rather than what is open. That needs a real menu click and steals focus, so it is off by default. Returns:
|
| app_open_panelA | Open a dockable panel by name, and confirm it appeared. Goes through View > Panels, because Altium exposes no scripted
way to show a panel and A panel that is already open is reported as such and NOT clicked.
Those menu entries are toggles, so clicking one you already have
would close it, and asking for a panel is not a request to lose
it. When the panel cannot be seen after the click (it may have
been open with no tab the scan reads), the entry is clicked once
more so the panel is left as it was, and the reply says so with
Args: name: the panel's name as View > Panels spells it, e.g. "Projects", "Messages", "PCB", "Properties". settle: how long to allow for it to appear. Returns:
|
| app_read_panelA | Read what is inside an open panel. Takes no focus and moves nothing, so it is safe while a user is
working. The panel must already be open: use Reads the WHOLE panel. It is not fast: Altium materialises its accessible tree lazily, so the first touch of a node costs about 116 ms and 162 rows is roughly thirty seconds. Slow and complete beats fast and partial. Returns:
|
| app_set_dropdownA | Choose an option in a combo box or drop list, and verify it. THESE WERE READABLE AND UNSETTABLE. combobox and droplist have
been reported by Three routes are tried, cheapest first: the option's own default action, an accessible selection, then a real click on it. The value is READ BACK afterwards, so a route that runs and changes nothing is reported rather than believed. Args: control_label: the combo's label. option: the option to choose, matched by name. dialog_title: which dialog, when several are open. list_only: report the options and change nothing. Returns:
|
| app_expand_tree_nodeA | Open or close a node in a tree, and verify the state changed. Trees were readable and could not be OPENED, so anything nested inside one did not exist as far as a caller was concerned. Args: control_label: the tree's label. node_name: the node to open, matched by name. expand: True to open, False to close. dialog_title: which dialog, when several are open. Returns:
|
| app_set_grid_cellA | Type into one cell of a grid, and read it back. ALTIUM'S RULE AND PROPERTY EDITORS TAKE THEIR INPUT THIS WAY. Selecting a row was possible before; changing anything in it was not. A grid cell is not an edit control until it is being edited, so the cell is activated first and the text goes to whatever editor the grid puts there. The value is then read back off the CELL, because the editor disappears when the edit commits. Args: control_label: the grid's label. row: the row, matched by name. column: the column name, or a numeric index. These grids leave many cells unnamed, and an index is then the only handle there is. text: what to type. dialog_title: which dialog, when several are open. list_only: report the row's cells and change nothing. Worth doing first, since it shows which columns have names. Returns:
|
| app_send_keysA | Send a key sequence to whatever currently has focus. THE THINGS THAT TAKE NEITHER A CONTROL NOR A MENU: a canvas shortcut, a grid that commits on Enter, a dialog answered with Escape, a chord like Ctrl+Shift+D. Every other tool here addresses a control; this addresses the keyboard. Space separated, each item a key or a '+' chord: Modifiers: ctrl, alt, shift. Keys: enter, escape, tab, space, backspace, delete, the arrows, home, end, pageup, pagedown and F1 to F12. An unknown name is refused and the known ones listed, rather than sent as nothing. THIS GOES WHEREVER FOCUS IS. Establish focus first, with app_click_menu or app_open_panel, and check the result afterwards: a keystroke has no read-back, so the reply says what was sent and never that it worked. |
| app_type_textA | Type literal text into whatever has focus. For a field that HAS a handle, app_set_dialog_control is better: it addresses the control by name and reads the value back. This is for the places with no handle to address, where typing is the only route in. Carries punctuation and case, since it sends characters rather than virtual keys. No read-back, for the same reason as app_send_keys. |
| app_context_menuA | Right click at a point: read the context menu, or pick from it. CONTEXT MENUS WERE ENTIRELY UNREACHABLE, and Altium puts a great deal in them that no top-level menu duplicates: what you can do to a component, a net, a polygon, a row in a panel. Driving the menu bar while ignoring these leaves most of the editor shut. With no Args: x, y: screen coordinates to right click. Panel and control rectangles from app_list_panels and app_set_dialog_control(list_only=true) give you these. item: the entry to choose. Nested entries take a '|' path, matched by name at each level like the menu bar. Returns:
Reading: |
| app_toolbarA | List toolbar buttons, or press one by name. Toolbars are the other half of the bar framework the menus use and were not addressed at all. Many carry a command with no menu equivalent, or reach in one click what the menu takes three to. With no |
| app_dialog_tabA | List a dialog's tab pages, or switch to one. PROPERTY DIALOGS HIDE MOST OF THEMSELVES BEHIND TABS. Nothing could switch one, so app_set_dialog_control only ever saw the front page and reported it as the whole dialog: a control on any other page read as a control the dialog does not have. With no |
| app_scroll_controlA | Scroll a list, grid or tree so more of it comes into view. A LONG LIST HIDES ITS OWN CONTENTS. A virtualised DevExpress grid exposes roughly what is on screen, so a row further down did not exist as far as a caller was concerned, and the reply gave no hint that anything was missing. Positive scrolls down, negative up. The reply reports whether
the rows actually changed: |
| app_activate_rowB | Invoke a row, rather than merely selecting it.
A click has no read-back, so the reply reports what was done and not what it caused. |
| app_screenshotA | Capture Altium, or one dialog, to a PNG. THE AGENT COULD NOT SEE THE UI. ui/ocr.py has been able to capture and read a window since it was written and none of it was exposed, so every judgement about what was on screen came from an accessible tree that omits anything drawn rather than placed. A picture settles what a tree cannot: which page is in front, whether a control is greyed, what a rendered dialog actually says. Args: path: where to write the PNG. Defaults to the workspace directory, so the file is somewhere findable. dialog_title: capture that dialog rather than the main window. Returns:
|
| app_canvasA | Click or drag on the editor canvas, at screen coordinates. THE CANVAS HAS NO NAMED CONTROLS, so every other tool here could not touch it. Placing, moving, rubber-band selecting and routing are pointer gestures and there was no way to make one. With NO READ-BACK IS POSSIBLE. The reply says what gesture was made and never what it did. Confirm with a bridge read, which can see the document, rather than trusting this. |
| app_wait_for_dialogB | Block until a dialog appears, and report which one. A COMMAND THAT RAISES A DIALOG RETURNS BEFORE THE DIALOG EXISTS. A caller that acted and then looked found nothing and concluded none was coming; the alternative was a fixed sleep long enough to be safe, which is the pattern this layer spent the day removing everywhere else. |
| app_ui_snapshotA | Everything on screen, in one call: menus, panels, dialogs, toolbars. ORIENTATION IS THE EXPENSIVE PART. Finding out what is available took four calls and knowing which four to make, and a caller who guessed wrong concluded a capability was missing. This is the UI equivalent of app_context: one call that answers "what am I looking at". Reads only. Takes no focus, moves no pointer, changes nothing, so it is safe while somebody is working. The menu BAR is listed because reading it needs no click; menu contents are not, because opening one does. |
| app_read_windowA | Read a window through UI Automation, which sees what MSAA cannot. THE LAYER THAT WAS MISSING. This project read Altium three ways: window text, which returns nothing for anything without a handle; MSAA, which handles the VCL dialogs well and the WPF ones not at all; and OCR on the pixels. UIA sits between the second and the third. It matters most for the case that forced OCR into existence. Altium's newer WPF dialogs have buttons that are NOT child windows, so EnumChildWindows finds nothing and MSAA has nothing to press. WPF is UIA-native, so those same buttons are ordinary elements here, with names, and they can be pressed properly with app_invoke_element. WHAT IT STILL WILL NOT SEE. Delphi's TLabel owns no handle and publishes no accessible object, so its text exists only as pixels. Use app_screenshot there; that is what OCR is for and why it stays. Returns:
|
| app_invoke_elementA | Press, set or expand an element through UI Automation patterns. PATTERNS ARE NOT A SIMULATED CLICK. MSAA offers little beyond a default action, which is why the rest of this layer falls back to moving a real mouse. UIA exposes what a control actually implements: Invoke to press, Value to set text, ExpandCollapse to open a node. Those are supported operations, so they move no pointer, take no focus, and cannot land on whatever happens to be under the cursor. That makes this the right tool for a WPF dialog, and for anything you want done while the user keeps working. A CLIENT THAT DOES NOT LIST THIS TOOL can still reach it through
the dispatcher: Args: name: the element's name or automation id. A Button of that name is preferred over a label carrying the same text. dialog_title: which dialog. Empty uses the frontmost open dialog, or the main window when no dialog is open. text: set this value instead of pressing. expand: "true" or "false" to open or close a node instead. Returns:
|
| app_get_statusA | Check if Altium Designer is running and get status information. Returns information about the Altium Designer process including:
MORE THAN ONE ALTIUM. MORE THAN ONE eda-agent SERVER. Returns: Dictionary with status information |
| app_contextA | Where you are, in one call. Run this before anything else. THE FOUR FACTS THAT EXPLAIN MOST "WHY DIDN'T THAT WORK". Each has cost a session on its own, and each was individually available and individually unasked for:
This composes existing reads rather than adding a bridge call, so it is cheap and cannot disagree with the tools it summarises. WHAT IT DOES NOT TELL YOU: which library component is current.
That is editor state with no read exposed, and the library
authoring tools depend on it. If a lib_add_* call lands somewhere
unexpected, set the target explicitly with
Returns:
|
| app_attachA | Connect to a running Altium Designer instance. This verifies Altium is running and the polling script is responding. The Altium_API.PrjScr script must be running (StartMCPServer) in Altium. Returns: Dictionary with attachment status |
| app_save_allA | Flush every dirty Altium document to disk. Mutation tools (pcb_place_tracks, move_component, modify_objects, ...) now mark documents as modified in-memory only. Changes stay fast because they skip per-operation disk writes. Call save_all at logical checkpoints, after a routing pass, before running DRC, or before closing, to persist everything. Detach also triggers save_all automatically, so you don't need this as the very last step. CHECK Returns:
Dict with |
| app_save_documentA | Save ONE open document:
Args: file_path: Absolute path of an open document. Empty saves the focused document. Returns:
|
| app_exit_active_commandA | Close a transaction a crashed handler left open in Altium. THE TOOL FOR "A command is currently active and save cannot be completed at this time". While that state is set, EVERY save is refused and the editor asks whether to write a copy instead. IT SURVIVES RESTARTING THE POLLING LOOP, because the state lives
in Altium's PCB server rather than in the script, and Escape in
the editor does not clear it either. MEASURED on 2026-08-25:
saves were being refused on a brand-new library, and the state
had been left hours earlier by Every PreProcess in this bridge is paired, including on its error paths, so this is not routine cleanup: it is recovery from a handler that DIED mid-transaction. AltiumScriptCentral ships the same one-line remedy as ExitActiveCommand.vbs. Calling it when nothing is outstanding is harmless. It saves nothing by itself. Run Returns: Dict reporting whether each server accepted the unwind, plus the count of still-modified documents before and after. |
| app_close_documentA | Close ONE open document, found by its full path, whatever has focus. Unlike closing through the workspace manager, which acts on the FOCUSED object, this closes the named document itself. It refuses a document that reads modified, and says whether it is really gone afterwards. The modified read can miss edits held in the editor, so save anything you care about first; a close of an edited document may still raise Altium's save prompt. Args: file_path: the document's full path, as app_list_documents reports it. discard_changes: close it even when it reads modified, and LOSE the unsaved edits: the modified flag is cleared first so no save prompt appears. For scratch copies and documents Altium changed by merely opening them, never for work. Returns:
|
| app_checkpointA | Snapshot the focused project so the session is revertible. Copies the project's design files into a content-addressed store under
the workspace (unchanged files are deduplicated, so repeat checkpoints
are cheap). Take one before any risky autonomous edit; restore with
Args: label: optional human note ("before routing pass"). save_first: flush dirty Altium docs to disk before snapshotting so the checkpoint reflects in-editor changes (default True). Returns:
The checkpoint manifest summary (id, created, file_count, ...).
With |
| app_list_checkpointsA | List saved checkpoints for the current workspace, newest first. |
| app_restore_checkpointA | Restore the focused project's files from a checkpoint. Overwrites design files with the snapshot contents. Close the project
in Altium (or expect a reload prompt) before restoring, since Altium
holds documents open. With Args:
checkpoint_id: id from Returns: {restored, removed, missing_blobs}. |
| app_detachA | Stop the Altium MCP polling loop. CALL THIS WHEN YOU'RE FINISHED. While the eda-agent MCP server is connected, a keep-alive thread pings Altium every 30 s, which keeps Altium's scripting engine held by the polling loop, Altium's own script-backed UI commands (some ribbon buttons, Parameter Manager actions, etc.) may be unresponsive until the loop is released. Call this tool once you've finished your Altium work for the session. It flushes every dirty document via save_all, then sends application.stop_server so the DelphiScript loop exits cleanly within ~500 ms and stops the Python keep-alive. Altium becomes immediately fully responsive. NOTE: After detach, the Altium script has fully stopped. To run more MCP tools later in the same Altium session the user must re-launch StartMCPServer via File -> Run Script. Don't detach until you're confident you're done. Returns: Dictionary confirming detachment |
| app_pingA | Test if the Altium script is responding and report script version. Verifies that:
Also reads SCRIPT_VERSION from the .pas that Altium has compiled and compares it to the version in the bundled on-disk Main.pas. A mismatch means Altium is running a stale cached script: close the script project in the Projects panel and reopen it to recompile. Re-running StartMCPServer does not recompile, and a restart of Altium alone has not always been enough. SCRIPT_VERSION only speaks for Main.pas. Each unit also reports a stamp that install-scripts writes from its content, and stale_units names any unit whose running compile differs from the files Altium loaded. Returns:
Dictionary with:
- success: True if Altium responded
- mcp_server_version: version of this eda-agent Python package
(from |
| app_get_reportA | Report the health of the MCP bridge, workspace, and Altium link. One call to diagnose the plumbing without touching the design: package version, the script version on disk vs. what Altium has compiled, whether Altium is up, the live IPC round-trip time, the workspace location, and how many request/response/stop files are sitting in it (a backlog of stale request_*.json usually means a dead or wedged poller). Returns: Dictionary with mcp_server_version, bundled_script_version, altium_running, altium_script_version, version_match, round_trip_ms (None if Altium is down), workspace_dir, workspace_exists, and a file_counts breakdown. |
| app_create_documentA | Create a new blank document of a given kind and save it to disk. Wraps IClient.OpenNewDocument + DoFileSave. The new document is
written to Args: kind: Document kind, 'PCB', 'SCH', 'PCBLIB', 'SCHLIB', 'OUTPUTJOB', or any other kind Altium's server module registers under. file_path: Absolute path where the new document should live. Use Windows backslashes. name: Optional display name. Defaults to the filename. add_to_project: Attach the new file to the focused project. Default True. Set False to leave it as a free document. The new document is focused before this returns, and Returns: Dictionary with kind, file_path, saved, focused, added_to_project. |
| app_list_documentsA | List all documents known to the current Altium workspace. Returns both project members and any free documents. Each entry
carries a Returns: List of document information dictionaries containing: - file_name: Document file name - file_path: Full file path - document_kind: Type of document (SCH, PCB, etc.) - loaded: True if the doc is resident in the editor server. False means it's a project member on disk whose editor state hasn't been opened yet. - modified: True if the editor holds unsaved edits. A false is a floor rather than a clean bill, since the flag does not always propagate from ProcessControl. app_save_all measures file timestamps instead of trusting it. |
| app_diag_workspaceA | Diagnostic: enumerate workspace files via Altium's FindFiles helper. Reports workspace_dir, the pattern used, match_count and the first 10 matching filenames. Used to validate the per-request file enumeration that the dispatcher relies on. |
| app_get_active_documentA | Get information about the currently active (focused) document. Returns: Dictionary with active document information: - file_name: Document file name - file_path: Full file path - document_kind: Type of document (SchDoc, PcbDoc, etc.) - modified: True if the editor holds unsaved edits. A false is a floor rather than a clean bill, since the flag does not always propagate from ProcessControl. Returns empty dict if no document is active. |
| app_set_active_documentC | Set a specific document as the active (focused) document. Args: file_path: Full path to the document to activate Returns: Dictionary with result of the operation |
| app_get_versionA | Get the version of Altium Designer. Uses Client.GetProductVersion internally. If that API is unavailable (older builds or restricted script context), the returned dictionary will omit "version" and include a "note" field instead. Returns: Dictionary with product_name and either: - version: Full version string (when Client.GetProductVersion works) - note: Explanation when the version API is unavailable |
| app_get_preferencesA | Get key Altium Designer preferences. Returns PCB preferences (snap grid, display unit) from the active board and schematic preferences (visible/snap grid) from the active schematic. Values are null if no PCB or schematic is currently open. Returns: Dictionary with "pcb" and "schematic" sub-objects containing grid and unit settings |
| app_run_menuA | Dispatch a menu command by path. DISPATCH IS NOT EXECUTION. This sends the command and cannot tell you it ran. Altium's
Use These paths are mapped to internal processes:
Anything else is REFUSED with UNMAPPED_MENU_PATH. The old
fallback guessed a MenuID out of the pipe-separated path and was
measured opening nothing while reporting success, so refusing
and pointing at Args: menu_path: Menu path using pipe separators (e.g., "File|Save All") Returns: Dictionary with dispatched, outcome_verified (always false), menu_path, and the process used. A reply the bridge could not parse is reported as a failure, not smoothed into a success. |
| app_set_intentA | Tell the dashboard what high-level task the agent is working on. The text is written to Args: intent: Short human-readable description (one line, <=240 chars). Returns:
|
| app_get_clipboardA | Get text content from the Windows clipboard. Returns whatever text is currently on the clipboard, which can be useful for reading data copied from Altium dialogs or reports. Returns: Dictionary with "text" containing the clipboard content. Returns empty string if clipboard is empty or non-text. |
| proj_createB | Create a new Altium project. Args: project_path: Full path for the new project file (.PrjPcb, .PrjLib, etc.) project_type: Type of project to create: - "PCB": PCB project (.PrjPcb) - "IntegratedLibrary": Integrated library project - "ScriptProject": Script project Returns: Dictionary with created project information |
| proj_openC | Open an existing Altium project. Args: project_path: Full path to the project file Returns: Dictionary with opened project information |
| proj_saveB | Save the current or specified project. Args: project_path: Optional path to specific project. If None, saves active project. Returns: Dictionary confirming save operation |
| proj_closeA | Close a project, saving its documents or discarding their edits.
WITHOUT SAVING, TWO LAYERS KEEP THE BRIDGE FROM WEDGING. A close with a modified member raises Altium's save prompt inside the polling loop, where the bridge cannot answer it. MEASURED on AD 26.10.1.6: after an edit IServerDocument.Modified reads False while the tab shows the sheet modified, so nothing gated on that read works. First, the handler clears the modified flag on every loaded member without reading it. MEASURED on a local scratch project: the close then raised no prompt and the file on disk was byte-identical. Second, if a prompt appears anyway, this answers it through UI Automation: "Save None", then "OK" once the dialog has retitled to "Confirm Not Saving", which is what shows the decisions changed. Pressing OK before that would save. The sequence was measured by hand; this tool running it has not run live. ALTIUM CLOSES THE FOCUSED PROJECT. MEASURED: a close naming a
project with no loaded document, while another project's board was
focused, closed that other project first. So the handler makes the
named project focused by showing one of its loaded documents, and
refuses, changing nothing, when it cannot. Every attempt compares
the open projects before and after: if anything else closed, it
stops without retrying and returns those paths as
IT ANSWERS ONLY FOR THIS PROJECT. It records the project's member
paths before closing and reads every path the prompt lists. If any
listed document is outside the project it presses nothing and
returns them, because answering would discard work in a project
nobody named. It also presses nothing when membership cannot be
established: no A document shared with another open project is a member of both,
so its unsaved edits are discarded here too. IF A PROMPT IS LEFT OPEN, answer it with Args:
project_path: project to close. Omit for the focused project;
Returns:
|
| proj_list_documentsA | List all documents in a project. Args: project_path: Optional path to specific project. If None, uses active project. Returns: List of document information dictionaries containing: - file_name: Document file name - file_path: Full file path - document_kind: Type of document |
| proj_add_documentB | Add an existing document to a project. Args: document_path: Full path to the document to add project_path: Optional project path. If None, uses active project. Returns: Dictionary confirming the operation |
| proj_remove_documentA | Remove a document from a project. Note: This only removes the document from the project, it doesn't delete the file. Args: document_path: Full path to the document to remove project_path: Optional project path. If None, uses active project. Returns: Dictionary confirming the operation |
| proj_get_parametersA | Get all parameters defined at the project level. Args: project_path: Optional project path. If None, uses active project. Returns: List of parameter dictionaries with name and value |
| proj_set_parameterC | Set a project-level parameter. Args: name: Parameter name value: Parameter value project_path: Optional project path. If None, uses active project. Returns: Dictionary confirming the operation |
| proj_push_parametersA | Copy all project-level parameters onto each loaded schematic sheet. Every project parameter is written as a document (sheet) parameter on
each LOADED schematic in the focused project, so title blocks can
reference project-wide values. Unloaded sheets are skipped -- call
Returns: Dict with param_count, sheets_updated, sheets_skipped_not_loaded, and params_pushed. |
| proj_get_netsA | Get net-to-pin connectivity from the compiled project netlist. CRITICAL for bulk queries, if you need connectivity for MORE
THAN ONE component or net, do NOT loop this tool. Call it
ONCE with no filters ( Compiles the project and returns pin-level net assignments. Args:
component: Filter by component designator. Empty = all.
net_name: Filter by net name. Empty = all.
project_path: Optional project path. If None, uses active.
limit: Max pin records (default 500). Raise for big boards.
force_recompile: Save all dirty docs, invalidate the
SmartCompile cache, recompile. Costs one extra
compile (~5-10 s on real designs). Use when you need
a guaranteed-fresh netlist (e.g., after the user
edited schematics in the UI). Pair with
Returns:
Dict with "pins", "count", "limit", "limit_hit" (true when
the list stopped at Examples: # PREFERRED, one unfiltered call, then filter locally: all_pins = proj_get_nets(limit=10000)["pins"] u1_pins = [p for p in all_pins if p["component"] == "U1"] |
| proj_export_netlistA | Write the compiled connectivity to a flat netlist file. Pulls the full pin-net table once (the same data as get_nets) and writes it as a standalone netlist that other tools can import. Two formats:
Single-pin and unnamed nets are included so the file is a faithful dump, not a routed-only view. Args: output_path: Destination file. Defaults to workspace/netlist. if omitted. net_format: "pads" (default) or "tabular". project_path: Optional project path; uses active if omitted. Returns: Dictionary with output_path, net_format, net_count, node_count. |
| proj_compileA | Compile a project to check for errors. This runs the project compilation which validates connectivity and checks for design errors. Args: project_path: Optional project path. If None, uses active project. Returns: Dictionary with compilation results including any errors/warnings |
| proj_load_sheetsA | Load every schematic sheet of a project into the Altium editor. Project-scope operations (query_objects, batch_modify, etc. with scope="project") only iterate sheets already resident in SchServer. A sheet listed as a project member via get_open_documents may still show loaded=false, meaning Altium hasn't opened its editor state. Call this tool first to force every sheet to load as a proper project member (no free documents). This is a no-op for sheets already loaded. Safe to call repeatedly. Args: project_path: Optional project path. If None, uses focused project. Returns: Dictionary with: - total_sheets: Total SCH sheets in the project - loaded: Sheets newly loaded by this call - already_loaded: Sheets that were already resident - failed: Sheets that could not be opened |
| proj_get_bomA | Export a full BOM from the compiled project. DATASHEET DISCIPLINE: The BOM is the canonical list of
manufacturer part numbers in this design. The response carries
Returns every component with designator, comment/value, footprint, library reference, and all pin-net connections. Args: project_path: Optional project path. If None, uses active project. limit: Max components to return (default 1000). Returns:
Dictionary with "components" array and "count", "limit",
"limit_hit" (true when the list stopped at |
| proj_get_component_infoA | Get full information about a single component. IMPORTANT, if you need info for MORE THAN ONE component, use
Performance note: pin nets are the only field that needs a
project compile, and a stale-cache compile on a multi-sheet
hierarchical project can take 30-60s. When you only need the
component's value, footprint, library reference, sheet, or
pin numbers/names (no nets), pass
DATASHEET DISCIPLINE: Before making any claim about this
component's pin function, voltage rating, timing, or electrical
behavior, fetch its datasheet (WebSearch + WebFetch if needed).
The parameters / comment / library metadata returned here are
NOT authoritative, only the manufacturer datasheet is.
Returns the component's designator, comment, footprint, library reference, parameters (when with_parameters=True), and every pin with name/number (and net assignment when with_pin_nets=True). Args: designator: Component designator (e.g., "U1", "R8", "C3") project_path: Optional project path. If None, uses active project. with_pin_nets: When True (default) compile the project and emit the flattened net for each pin. Set to False to skip the compile and get a sub-second metadata-only response. with_parameters: When True (default) include the parameter dict. Set to False for the cheapest possible probe. timeout: Optional bridge poll-timeout override (seconds). Use a higher value (e.g., 90) when keeping with_pin_nets True on large hierarchical projects. Returns:
Dictionary with designator, comment, footprint, lib_ref,
sheet, pins array (each with pin/name and, when requested,
net), and (when requested) parameters dict, plus
|
| proj_get_component_info_manyA | Full per-component info for MANY designators in ONE round-trip. PREFER THIS over looping Set DATASHEET DISCIPLINE: parameters / comment / library metadata
in the response are NOT authoritative. Before reasoning about
any component's pin function, voltage rating, timing, or
electrical behavior, fetch its manufacturer datasheet. The
response carries Args:
designators: List of component designators.
project_path: Optional project path. If None, uses active.
with_pin_nets: When True (default) compile once and emit
the flattened net for each pin on every component.
Set False to skip the compile.
with_parameters: When True (default) include each
component's parameter dict.
timeout: Optional bridge poll-timeout override (seconds).
Raise this when keeping Returns:
Dict with components[], matched, requested, not_found[],
plus |
| proj_export_pdfB | Export the active document to PDF. Args: output_path: Full path for the output PDF file Returns: Dictionary confirming export |
| proj_cross_probeA | Jump to and highlight a component in the schematic or PCB. Args: designator: Component designator to find (e.g., "U1", "R8") target: "schematic" or "pcb" Returns: Dictionary confirming the operation |
| proj_get_statsA | Get design statistics from the compiled project. Returns counts of sheets, components, pins, and nets. Args: project_path: Optional project path. If None, uses active project. Returns: Dictionary with sheets, components, pins, nets counts |
| proj_get_board_infoA | Get PCB board information, outline vertices, layer stack, origin. IT DOES NOT REQUIRE A PCB TO BE ACTIVE, which is what this used to claim. The handler resolves ANY open board, so with a schematic focused it answers about some other document. MEASURED: with a schematic active and a two-document project focused, it returned an outline belonging to neither, and gave no way to tell.
Returns: Dictionary with origin_x, origin_y, board_path, outline (vertex array), and layers (active copper layer names) |
| proj_annotateA | Annotate schematic designators programmatically, no dialog, no user interaction. Compiles the project, iterates every schematic sheet, collects all unlocked components, sorts them by the chosen order, and assigns sequential designators per alpha prefix (R1, R2, ... C1, C2, ... U1, U2, ...). Designator prefixes are preserved from the current value (e.g., "R?" or "R13" both keep the "R" prefix). Locked designators (Designator.IsLocked = True) are skipped. All changes are wrapped in SchServer.ProcessControl.PreProcess/PostProcess for undo support. Args: order: Annotation traversal order: "down_then_across" (default: row-major top-to-bottom, left-to-right) "up_then_across" (row-major bottom-to-top, left-to-right) "across_then_down" (column-major left-to-right, top-to-bottom) "across_then_up" (column-major left-to-right, bottom-to-top) "none" (reset all designators to "?") Returns: Dictionary with: - success: True - order: the order that was applied - renamed: count of components renumbered - reset: count reset to "?" (only for order="none") - skipped_locked: count of locked components left untouched - documents_processed: count of schematic sheets visited - programmatic: True (marks this as the non-interactive path) |
| proj_run_outputA | Generate manufacturing output files from the active PCB. Note: These may open Altium's export dialogs for configuration. Args: output_type: Type of output, "gerber", "drill", "pick_place", "ipc_netlist" output_path: Optional output directory/file path Returns: Dictionary confirming generation |
| proj_get_focusedB | Get information about the currently focused project. Returns: Dictionary with project information: - project_name: Name of the project - project_path: Full path to the project file - document_count: Number of documents in the project |
| proj_export_stepA | Export the open PCB to a STEP 3D model file. The board is focused first, since the export acts on the focused
view. If output_path is omitted, Altium may show a file-save
dialog. Args: output_path: Full path for the output .step file (optional) Returns:
|
| proj_export_dxfA | Export the active PCB to DXF (AutoCAD) format. Requires an active PCB document. If output_path is omitted, Altium may show a file-save dialog. Args: output_path: Full path for the output .dxf file (optional) Returns: Dictionary confirming the export |
| proj_export_imageA | Export the active schematic / PCB document, silent (no dialog). Only The PDF path uses Altium's
The Pascal side deletes any pre-existing file at Args:
output_path: Full path for the output file. The directory must
already exist. The extension should be Returns:
Dictionary confirming the export with the resolved path,
format, width, height, and the scoped schematic. Sets
|
| proj_list_outjob_containersA | List all output containers defined in an OutJob file. OutJob files define output configurations (Gerber, PDF, BOM, etc.)
organized into named containers. Use this to discover what outputs
are available before running them with Args: outjob_path: Path to the .OutJob file. If omitted, uses the first OutJob found in the focused project. Returns: Dictionary with "outjob_path" and "containers" array (each: name, type, group) |
| proj_run_outjobA | Execute a specific output container from an OutJob file. First use SUCCESS MEANS A FILE WAS WRITTEN. Running a container proves only
that Altium was asked to. One bound to a managed release, or with
its outputs switched off, runs cleanly and writes nothing, and
this used to report That check covers Args: container_name: Name of the output container to execute outjob_path: Path to the .OutJob file. If omitted, uses the first OutJob found in the focused project. fresh_window_seconds: files modified up to this many seconds before the run started still count as written, for file systems with coarse timestamps. Default 5s. Returns:
|
| proj_run_outjob_allA | Run every container in an OutJob and report what each produced. Lists containers via Args:
outjob_path: Path to the .OutJob. Omit to use the first one
in the focused project.
include_files: When True (default) the response includes a
per-container file listing with sizes / mtimes / a
Returns:
Dict with |
| proj_generate_fab_packageA | Generate a fabrication package from an OutJob (Gerbers, NC drill, IPC-356, pick-and-place, assembly, BOM) and report every file produced. Altium has no per-format export process for Gerber / NC-drill / IPC-356 / P&P: those exist only as OutJob output containers. This runs every container in the project's OutJob, scans each container's output directory, and returns a consolidated manifest. Optionally also exports a STEP 3D model and a DXF (which are separate PCB export processes, not OutJob containers). Prerequisite: the project must have an OutJob whose fab containers are configured and enabled: the script cannot enable outputs that are off in the OutJob editor. Args: outjob_path: path to the .OutJob; omit to use the first one in the focused project. include_step: also export a STEP 3D model of the active PCB. include_dxf: also export a DXF of the active PCB. fresh_window_seconds: files modified within this window before a container ran still count as newly produced. Returns: {"ok", "outjob_path", "containers_run", "results" (per-container with output_dir + files), "extras" (step/dxf results), "all_files" (flat list of newly-produced file paths)}. |
| proj_list_variantsB | List all project variants with their component overrides. Compiles the project and returns every variant definition including component variation details (Fitted / Not Fitted / Alternate) and any parameter overrides. Args: project_path: Optional project path. If None, uses active project. Returns: Dictionary with "variants" array and "count". Each variant has name, description, and variations array (designator, kind, alternate_part, parameters). |
| proj_get_active_variantA | Get the currently active project variant. Args: project_path: Optional project path. If None, uses active project. Returns: Dictionary with variant "name" and "description". Returns "[No Variations]" if no variant is active. |
| proj_set_active_variantB | Switch the active project variant. Args: variant_name: Name of the variant to activate project_path: Optional project path. If None, uses active project. Returns: Dictionary confirming the switch |
| proj_export_variant_matrix_csvA | Write the variant fitted/not-fitted matrix to a CSV. Builds the conventional component-by-variant table: one row per
flattened component, one column per variant, each cell
Args:
output_path: Destination .csv. Defaults to
Returns: {"output_path", "component_count", "variant_count"} or an error. |
| proj_print_all_variantsA | Export a PDF for every project variant. Loops the project's variants; for each it sets that variant active and
runs the (silent) PDF export, writing one Args: output_dir: Folder for the per-variant PDFs. Defaults to the workspace directory. project_path: Optional project path. If None, uses the focused project. Returns:
{"exported": [{variant, output_path, ok, error}], "count"} plus
|
| proj_create_variantA | Create a new project variant. After creating, use Args: name: Name for the new variant description: Optional description project_path: Optional project path. If None, uses active project. Returns: Dictionary confirming creation with name and description |
| proj_delete_variantA | Delete a project variant, with every component variation in it. THIS IS NOT REVERSIBLE FROM HERE. A variant's entries record which
components are not fitted and which carry an alternate part, and
The variant is addressed by name rather than index, because removing one renumbers the rest: two deletions by index taken from a single listing would remove the wrong second variant. Args: variant_name: name of the variant to remove. project_path: optional project path; defaults to the focused project. Returns:
|
| proj_list_openA | List all currently open projects in the Altium workspace. Returns: Dictionary with "projects" array (each: project_name, project_path, document_count) and "count" |
| proj_get_messagesA | Get all messages from the Messages panel (compile errors, ERC violations, etc.). Compiles the project first so violation data is current, then returns every violation with its text, severity, and source document. Args: project_path: Optional project path. If None, uses active project. Returns: Dictionary with "messages" array (each: message, severity, source) and "count" |
| proj_find_componentA | Search for components across all project sheets. DATASHEET DISCIPLINE: Results carry Performs a case-insensitive partial match against the chosen property. Args: search_text: Text to search for (e.g., "U1", "100nF", "LM317") search_by: Property to search, "designator", "value", or "comment" (default "designator") project_path: Optional project path. If None, uses active project. Returns:
Dictionary with "results" array (each: designator, comment, footprint,
lib_ref, sheet, location_x, location_y) and "count", plus
|
| proj_get_connectivityA | Get pin-to-net connectivity for a specific component. IMPORTANT, if you need connectivity for MORE THAN ONE
component, use Compiles the project and returns every pin with number, name, net assignment, and electrical type. Args: designator: Component designator (e.g., "U1", "R8") project_path: Optional project path. If None, uses active. force_recompile: SaveAll + invalidate cache + recompile before reading. Use when you need a guaranteed-fresh netlist. DATASHEET DISCIPLINE: pin_name in the response comes from the
symbol, which can be wrong. Before reasoning about the pin's
function (input vs output, drive strength, voltage range,
active level), fetch the manufacturer datasheet and verify
against its pin-description table. The response carries
Returns:
Dict with designator, comment, sheet, pin_count, pins[],
plus |
| proj_get_connectivity_manyA | Pin-net connectivity for MANY components in ONE round-trip. PREFER THIS over looping DATASHEET DISCIPLINE: pin_name on every component in the
response comes from the symbol and can be wrong. Before
reasoning about pin functions, fetch each part's manufacturer
datasheet. The response carries Args: designators: List of component designators. project_path: Optional project path. force_recompile: SaveAll + invalidate cache + recompile before reading. Use when you need a guaranteed-fresh netlist. Returns:
Dict with components[], matched, requested, not_found[],
plus |
| proj_force_recompileA | Flush all dirty docs, invalidate the compile cache, and recompile. Use this when you need a guaranteed-fresh netlist, e.g. immediately before re-running a connectivity check the user has disputed. Returns prev / new compile tick so you can verify the recompile actually happened. Returns: Dict with recompiled, prev_compile_tick, new_compile_tick, project path. |
| proj_get_compile_freshnessA | Report the age of the cached netlist and which docs are dirty. Use this when you're about to disagree with the user about connectivity, first check how stale the netlist you're reading actually is, and whether any open editor docs haven't been saved yet. A dirty doc means the netlist does NOT reflect what the user is looking at. Returns: Dict with compile_age_ms, compile_cached (bool), ttl_ms, open_doc_count, dirty_doc_count, dirty_docs[], project. |
| proj_import_documentA | Import a document into the focused project from an external path. Copies the file into the project directory (if not already there), adds it to the project, and saves the project file. Args: source_path: Full path to the source document (SchDoc, PcbDoc, etc.) Returns: Dictionary with success status, source_path, and dest_path |
| proj_get_pathB | Get the full path of the currently focused project file. Returns: Dictionary with project_path, project_dir, and project_name |
| proj_set_document_parameterA | Set a document-level parameter on a specific schematic sheet. Useful for per-sheet title block data (e.g., "SheetTitle", "Revision"). If the parameter already exists it is updated; otherwise a new hidden parameter object is created on the sheet. NOTE: the target sheet must already be loaded as a proper project
member. Call The write is persisted to disk immediately via the IServerDocument
API, no subsequent Args: file_path: Full path to the schematic document (.SchDoc). Use Windows-style backslashes (e.g. C:\path\Sheet.SchDoc), not forward slashes. name: Parameter name value: Parameter value Returns:
Dictionary with file_path, name, value, and dirty=true
(the in-memory flag; the disk write already happened, so no
|
| proj_compare_sch_pcbA | Compare schematic and PCB component counts. Compiles the project and compares physical component counts between the
schematic and the primary PCB document, via the component mappings
(matched + side-only) -- the same authoritative path as
DATASHEET DISCIPLINE: If the diff reveals mismatched or missing parts and you're proposing a fix, the datasheets of the parts involved are authoritative on their pinout and behavior, fetch them before suggesting a footprint change or pin reassignment. Args: project_path: Optional project path. If None, uses active project. Returns:
Dictionary with sch_components, pcb_components, components_match
(bool), and pcb_path. (Net-count comparison is not provided here;
use |
| proj_sync_pcbA | Push schematic changes to PCB (ECO): Design ▸ Update PCB Document. IMPORTANT: this is NOT silent. Altium's ECO (change-review) dialog is non-suppressible by design, so this fires the real ECO and then BLOCKS on a modal dialog until a human clicks "Execute Changes". Do not call it in an unattended/headless run: it will hang the Altium-side polling loop until someone interacts. (There is no documented silent flag; the prior implementation called a non-existent process id and silently did nothing.) The server:
THE DIRECTION DEPENDS ON FOCUS, so the tool sets it. A schematic in focus makes Altium refuse with "Cannot compare a source document against its owner project"; the PCB in focus with Action=UpdateOther updates the SCHEMATIC from the board, which is what this tool used to send, and an ECO came up with the SchDoc as the affected document. Refuses with WRONG_FOCUS when the PCB cannot be focused. Before executing, check that the ECO's affected documents are the PcbDoc. What the result does NOT tell you: whether the dialog was accepted.
For unattended board population without a schematic, use
Returns: Dictionary with success, pcb_path, before/after mapping counts, components_added_to_pcb, components_removed_from_pcb, components_in_sync (component presence only, see above), and dialog_outcome_verified. |
| proj_sync_schematicA | Push PCB changes back to schematic (back-annotate ECO). Attempts silent execution. Equivalent to Design > Update Schematic in Altium Designer. Mirror of update_pcb: compiles, records before-state mappings, invokes PCB:UpdateSchematicFromPCB with silent-mode parameter flags (DisableDialog, Silent, NoConfirm, AutoApply), recompiles, and reports the after-state delta. Modern Altium versions execute without a dialog; older versions may still require manual confirmation (flagged via dialog_may_have_opened). Returns: Dictionary with success, pcb_path, before/after mapping counts, components_added_to_schematic, components_removed_from_schematic, in_sync, and dialog_may_have_opened flag. |
| proj_get_differencesA | Get detailed differences between schematic and PCB netlist. Compiles the project and uses component mappings to find:
Args: project_path: Optional project path. If None, uses active project. Returns: Dictionary with matched_components, extra_in_schematic (array), extra_in_pcb (array), and in_sync (bool) |
| proj_lock_designatorA | Lock or unlock component designators to prevent re-annotation. When locked, designators are preserved during annotation operations. Use designator="all" to lock/unlock all components on the active sheet. Args: designator: Component designator (e.g., "U1", "R3") or "all" for all components lock: True to lock, False to unlock (default True) Returns: Dictionary with designator, locked status, and count of affected components |
| proj_get_optionsB | Get project options: output path, hierarchy mode, compiler settings. Returns configuration details including output directory, hierarchy mode, document counts, variant count, channel settings, and net naming options. Args: project_path: Optional project path. If None, uses active project. Returns: Dictionary with project_name, output_path, hierarchy_mode, logical_document_count, physical_document_count, variant_count, channel settings, and net naming options |
| lib_create_symbolA | Create a new schematic symbol in the active library. Args:
name: Component name
designator_prefix: Default designator prefix (e.g., "U", "R", "C")
description: Component description
part_count: For multi-part components (quad op-amp, dual gate,
etc), the number of sub-parts. Pins added via lib_add_pins
with Returns: Dictionary with created symbol information |
| lib_create_ic_symbolA | Create a COMPLETE, discipline-compliant IC symbol in ONE call. You decide the functional grouping (inputs/power/control on the LEFT, outputs/status on the RIGHT -- discipline rule 18); this lays them out cleanly and emits the whole symbol: the body rectangle (Altium-yellow fill) plus every pin, grid-aligned with the top-left pin's wire-end at the origin (rule 14), in one create + one bulk add_pins + one rectangle. Args:
name: Component name.
left_pins: Pins on the LEFT side, top-to-bottom. Each a dict
with Returns: Dict with the symbol name, pin count, body extent, and the per-step bridge results. |
| lib_create_passive_symbolA | Create a standard 2-pin PASSIVE symbol in ONE call. Draws the recognizable glyph for a resistor / capacitor /
polarized_capacitor / inductor / diode / led / crystal / fuse,
with pin 1 on the left and pin 2 on the right. Composes
Args: name: Component name (e.g. "R_0402"). kind: "resistor" | "capacitor" | "polarized_capacitor" | "inductor" | "diode" | "led" | "crystal" | "fuse" (aliases r/c/cap_pol/electrolytic/cp/l/d/xtal/f accepted). designator_prefix: default by kind (R/C/L/D/Y/F) if omitted. description: Component description. Returns: Dict with the symbol name and per-step bridge results. |
| lib_set_current_componentA | Make a named component the editor's current selection in the active SchLib. Required before bulk-editing a specific component's pins,
rectangle, or parameters via Use this between switching components: lib_set_current_component("MyIC") modify_objects("ePin", scope="active_doc", filter="Location.X=200", set="Orientation=2") lib_set_current_component("MyOtherPart") modify_objects("ePin", scope="active_doc", filter="Location.X=200", set="Orientation=2") Args: component_name: Component name (LibRef) in the active SchLib. Returns:
Dict with |
| lib_add_pinsA | Add MANY pins to the current symbol in ONE call. PREFER THIS over adding pins one at a time (there is no singular variant). A 48-pin IC symbol built one pin at a time would be 48 LLM turns; with this tool it's one turn + one PreProcess/PostProcess + one save. Args:
pins: List of pin dicts, each with:
- designator (str, required)
- name (str, required)
- x, y (int, mils), pin endpoint
- length (int, mils, default 200)
- rotation (int, default 0), 0/90/180/270
- electrical_type (str, default "passive"), one of
input/output/bidirectional/passive/open_collector/
open_emitter/power/hiz/io
- hidden (bool, default False)
- owner_part_id (int, optional). For multi-part
components (e.g. quad op-amp). 1..part_count picks a
specific sub-part; 0 shares the pin across all parts
(typical for V+ / V- power pins on a quad). Omit for
single-part symbols.
- symbol_outer_edge (str, optional). IEEE decoration on
the pin's outer edge. "dot" draws the inversion bubble
of an active-low pin. Omit for none.
- symbol_inner_edge (str, optional). Same, inner edge.
"clock" draws the clock wedge. The two are
independent, so an inverted clock sets both.
Either field also accepts any other TIeeeSymbol name
("schmitt", "open_collector", "active_low_input", ...)
or a bare ordinal.
- show_name / show_designator (bool, optional). Whether
the pin's name and number are DRAWN. Different from
Example, one stage of a dual op-amp (sub-part 1) with shared power pins (sub-part 0): lib_add_pins(pins=[ {"designator": "1", "name": "OUT1", "x": 0, "y": 0, "rotation": 180, "electrical_type": "output", "owner_part_id": 1}, {"designator": "2", "name": "IN1-", "x": 0, "y": 100, "rotation": 180, "electrical_type": "input", "owner_part_id": 1}, {"designator": "3", "name": "IN1+", "x": 0, "y": 200, "rotation": 180, "electrical_type": "input", "owner_part_id": 1}, {"designator": "8", "name": "V+", "x": 0, "y": 400, "rotation": 180, "electrical_type": "power", "owner_part_id": 0}, ]) Returns: Dict with added, failed, total counts. |
| lib_add_symbol_rectangleA | Add a rectangle to the current symbol body. ADD THE BODY BEFORE THE PINS. Altium exposes no z-order on
schematic primitives, so drawing order is insertion order and
there is no send-to-back to correct it afterwards. A rectangle
given a Args: x1: First corner X in mils y1: First corner Y in mils x2: Opposite corner X in mils y2: Opposite corner Y in mils fill_color: Fill color index (-1 = no fill) border_color: Border color index Returns: Dictionary confirming rectangle addition |
| lib_add_symbol_textA | Add MANY body-text items to the current symbol in ONE call. PREFER THIS over adding text one at a time (there is no singular variant). Free text on a symbol is an Altium ISch_Label: the polarity marks, pin-group headings and "NC" annotations that carry meaning the geometry alone does not. Args:
texts: List of text dicts, each with:
- text (str, required). Empty strings are refused,
not placed: an empty label is invisible and
unselectable, and only turns up later as a stray
object.
- x, y (int, mils)
- rotation (int, default 0), 0/90/180/270
- font_size (int, default 10). Altium's own font size,
the number its font manager takes. NOT mils, and not
converted from mils: the relationship between the two
is not documented anywhere this project can verify, so
a conversion here would silently resize every item.
- font_name (str, default "Arial")
- bold, italic (bool, default False)
- owner_part_id (int, optional). Same meaning as in
Returns:
Dict with |
| lib_add_symbol_linesA | Add MANY lines to the current symbol body in ONE call. PREFER THIS over adding lines one at a time (there is no singular variant). A 12-line LED diode glyph drawn line-by-line would be 12 LLM turns + 12 IPC round-trips + 12 redraw passes; this tool does it in one turn with a single PreProcess/PostProcess pair and one editor redraw at the end. Args:
lines: list of dicts, each with keys Returns:
Dict with |
| lib_create_footprintC | Create a new PCB footprint in the active library. Args: name: Footprint name description: Footprint description Returns: Dictionary with created footprint information |
| lib_create_standard_footprintA | Create a COMPLETE standard footprint in ONE call. Composes parametric geometry with the bulk authoring tools: makes the footprint, then emits every pad + the silkscreen outline + the courtyard rectangle in two batched round-trips. Supply the package's recommended land-pattern dimensions from the datasheet (this carries no part library -- the numbers you pass ARE the footprint). Args: name: Footprint name (e.g. "SOIC-8_3.9x4.9"). family: "chip" (2-pin passive) | "sip" (single-row header) | "dual" (SOIC/SOP/SON/SOT/DIP) | "header" (2-row pin/box header, IDC, SWD/JTAG -- column-major odd/even numbering) | "tab" (power/tab package: SOT-223, DPAK/D2PAK, TO-220 -- signal pins one side + a large tab pad opposite, pass tab_w & tab_h) | "quad" (QFP/QFN) | "bga" (ball grid -- pass rows & cols). SOT-23 is "dual" with pin_count=3. Through-hole (DIP/header/TO-220) = any family with hole > 0. pin_count: total pads (2 for chip; even for header; n signal pins for tab; divisible by 4 for quad; ignored for bga). rows, cols: BGA ball grid dimensions (bga family only). exposed_pad: centre thermal/exposed pad size (mils) for QFN/QFP (quad family); 0 = none. Gets designator pin_count+1. tab_w, tab_h: tab pad size (mils) for the "tab" family; the tab gets designator pin_count+1 (tie it to a signal pin in the schematic). skip: BGA ball designators to omit (depopulation), e.g. ["A1","E5"] (bga family only). pitch: pad centre-to-centre within a row (mils). pad_w, pad_h: pad size (mils). TWO MEANINGS, kept for the callers that rely on them: pad_w is the pad's X size in every family but quad, so in dual (rows left and right) and chip it runs ACROSS the row, along the span, while in sip, header and tab it runs along the row; in quad each side turns the pad and pad_w runs ALONG the row. For a footprint from a package drawing use lib_create_footprint_from_package, which sizes the lands by IPC-7351B from the terminal's lead_length (along the span) and lead_width (across it). row_span: centre-to-centre between the two rows / opposite sides (mils). Required for dual and quad. shape: pad shape (default "roundrect"); corner_radius is its %. silk: draw a silkscreen body outline (TopOverlay). courtyard: clearance (mils) past the extent for the courtyard rectangle (Mechanical1); 0 disables it. body_w, body_h: package body for the silk outline; default to the pad extent. hole: drill size (mils). >0 makes through-hole pads (DIP / header / axial): pin 1 rectangular, the rest round. Returns: Dict with the footprint name, pad/track counts, extent, and the per-step bridge results. |
| lib_create_footprint_from_packageA | Create a COMPLETE footprint in the open PcbLib from a package drawing. Takes the package as the datasheet draws it, not a pad list: the lands come from IPC-7351B (toe, heel and side fillets with the tolerance stack-up) for the family and density asked for. Writes the pads (rounded rectangles with their corner ratio, rotation, holes, slots, non-plated holes), paste windows over an exposed pad with the pad's own paste closed, silkscreen kept clear of the copper with a pin 1 dot, the body outline and a .Designator on the assembly layer, the courtyard, and the footprint height from the package's maximum A. Origin at the package centroid. Every length goes in millimetres, unrounded. It then READS THE PADS BACK (lib_get_pad_geometry) and compares count, centres, sizes, rotation, shape, holes and any manual paste or mask expansion with what was sent, within one internal unit. A difference is a failure, not a warning. DATASHEET DISCIPLINE: transcribe the package from the
manufacturer's drawing fetched in this conversation, each
dimension as min/nom/max with its page and figure, and name the
datasheet in Args:
package: the PackageSpec as an object (or its JSON text):
Returns:
|
| lib_add_footprint_padA | Add a pad to a footprint: the named one, or the current one. Args:
designator: Pad designator (e.g., "1", "2")
x: X coordinate in mils
y: Y coordinate in mils
x_size: Pad X size (default 60 mil)
y_size: Pad Y size (default 60 mil)
hole_size: Drill hole size (0 for SMD). A drilled pad
is forced through-hole (MultiLayer); a hole-less pad is
SMD on Returns: Dictionary confirming pad addition |
| lib_add_footprint_padsA | Add MANY pads to the current footprint in ONE call. PREFER THIS over looping Args: pads: List of pad dicts, each with: - designator (str, required) -- e.g. "1", "2", "A1" - x, y (int, mils), pad centre - x_size, y_size (int, mils, default 60) - hole_size (int, mils, default 0 = SMD) - shape (str, default "rectangular"), one of round / rectangular / octagonal / roundrect (modern IPC rounded-rectangle SMD). Oval = round with x_size!=y_size. - corner_radius (int %, default 25) for shape="roundrect" - rotation (float deg, default 0) - layer (str, default "TopLayer"). Only used for SMD pads (hole_size=0); a drilled pad is forced through-hole (MultiLayer). Use "BottomLayer" for bottom-side SMD. Optional, written only when given: - hole_length (slot length, above hole_size: a slotted hole hole_size wide, along the pad's X before rotation) - plated (false: a non-plated hole) - paste_expansion, mask_expansion (a manual expansion that overrides the design rule; minus the larger pad side closes the paste opening) The reply counts them (slots, unplated, expansions) and any write this Altium build refused (property_failures). Example, a 4-pad 0402 + corner pad in one call: lib_add_footprint_pads(pads=[ {"designator": "1", "x": -25, "y": 0, "x_size": 30, "y_size": 40}, {"designator": "2", "x": 25, "y": 0, "x_size": 30, "y_size": 40}, ])
Returns: Dict with added, failed, total counts. |
| lib_add_footprint_trackA | Add a track to the current footprint (for silkscreen/courtyard). Args: x1: Start X in mils y1: Start Y in mils x2: End X in mils y2: End Y in mils width: Track width in mils layer: Layer name. Default "TopOverlay" (silkscreen). Any Altium layer is accepted, e.g. "BottomOverlay" or "Mechanical1".."Mechanical16" for courtyard / assembly outlines. footprint_name: footprint to write into. Empty uses the editor's current footprint; a name makes that footprint current first and refuses if it cannot. units: "mil" (default) or "mm", for every length and coordinate here, kept exact rather than rounded to whole mils. Returns: Dictionary confirming track addition |
| lib_add_footprint_tracksA | Add MANY tracks to the current footprint in ONE call. PREFER THIS over looping Args: tracks: List of track dicts, each with: - x1, y1, x2, y2 (int, mils) -- endpoints - width (int, mils, default 10) - layer (str, default "TopOverlay" silkscreen). Any Altium layer name, e.g. "BottomOverlay" or "Mechanical1".."Mechanical16" for courtyard/assembly. Example, a 100x60 mil silkscreen rectangle in one call: lib_add_footprint_tracks(tracks=[ {"x1": -50, "y1": -30, "x2": 50, "y2": -30}, {"x1": 50, "y1": -30, "x2": 50, "y2": 30}, {"x1": 50, "y1": 30, "x2": -50, "y2": 30}, {"x1": -50, "y1": 30, "x2": -50, "y2": -30}, ])
Returns: Dict with added, failed, total counts. |
| lib_add_footprint_regionsA | Add solid polygon regions to a PcbLib footprint in ONE call. What a footprint needs beyond pads and lines: paste windows over an exposed pad (on TopPaste, with the pad's own paste closed by a negative paste_expansion in lib_add_footprint_pads), or any filled shape on a mechanical or overlay layer. Args:
regions: list of Returns:
Dict with added, failed, bad_points, unknown_layers, total. A
region refused here before sending is listed in
|
| lib_add_footprint_arcA | Add an arc to the current footprint. Args: x_center: Center X in mils y_center: Center Y in mils radius: Arc radius in mils start_angle: Start angle in degrees end_angle: End angle in degrees width: Line width in mils layer: Layer name. Default "TopOverlay" (silkscreen). Any Altium layer accepted, e.g. "Mechanical1".."Mechanical16" for pin-1 / assembly markers. footprint_name: footprint to write into. Empty uses the editor's current footprint; a name makes that footprint current first and refuses if it cannot. units: "mil" (default) or "mm", for every length and coordinate here, kept exact rather than rounded to whole mils. Returns: Dictionary confirming arc addition |
| lib_add_footprint_textA | Add a text primitive to a PcbLib footprint. Trap baked into this handler: in a PcbLib, adding a primitive
only to the footprint does NOT register it with the placement
editor -- the text shows up only after a save+reload. This
tool adds the text to BOTH the footprint and the underlying
board, then broadcasts Args:
text: The string to place. Required.
x, y: Coordinates in mils, relative to the FOOTPRINT's origin,
which is what the handler has always actually done
( Returns:
Dict with |
| lib_extract_intlibA | Extract .SchLib + .PcbLib sources from an .IntLib. Opens the integrated library in Altium, runs the editor's
After this returns with Args: intlib_path: Absolute path to the .IntLib file. Returns:
Dict with |
| lib_get_footprintsA | Enumerate every footprint in a PcbLib. PcbLib counterpart to Args: library_path: Optional .PcbLib path to focus first. Defaults to the focused document. Returns:
Dict with |
| lib_audit_footprint_policiesA | Sweep a PcbLib and flag footprints that break the library's own conventions: inconsistent layer usage, pad rules, pin-1 markings, courtyard, silkscreen, 3D models, designator style. For each policy dimension it learns the library's DOMINANT convention
across all footprints and reports every footprint that deviates (so it
works on any house style without hard-coded rules). Pass Each finding names the footprint, the dimension, and the expected vs actual value: enough to drive a fix, not just a report. Designators are checked for presence, layer, height, and for sitting on
the footprint's AVERAGE PAD CENTRE rather than the library origin (which
is arbitrary). Tune the centring window with
Geometry is read with the bulk Args: library_path: Optional .PcbLib to focus first; defaults to the focused library. policy: Optional explicit conventions to enforce; omitted dimensions are inferred from the library. Returns |
| lib_convert_designators_to_strokeA | Convert every TrueType A TrueType PCB text will not persist a position change made through
This clears Returns |
| lib_reload_libraryA | Close and reopen a PcbLib so Altium rebuilds its caches from disk.
SAVE FIRST: this does not save, and closing a dirty document loses the
edits or raises a prompt. |
| lib_probe_designatorA | Diagnostic: dump one footprint's raw designator geometry. Read-only. Returns the footprint origin and bounding rectangle, the pad
extents, and the Returns |
| lib_fix_designatorsA | Bring every footprint's Nothing is hard-coded. The target layer, its raw ordinal, the norm
height and the centring tolerance are all inferred from this library
(see DEFAULTS TO A DRY RUN. With Applying RUNS TO CONVERGENCE: apply, save, reload the PcbLib, re-plan, repeat until nothing is left. The reload is mandatory, not cosmetic: Altium caches each text's bounding rectangle at load and never refreshes it when the text moves or is resized, so a second pass without a reload would centre against stale geometry and shove designators off the part. Resizing a text also changes its box, so height fixes and centring settle over successive passes rather than one. PARTIAL SUCCESS IS EXPECTED AND REPORTED, NOT HIDDEN. A small number of
designators (a handful per library) do not persist a position change
through Altium's save for reasons not yet diagnosed: the write reads
back changed but the value reverts on reload. Rather than loop forever or
claim success, the tool stops when a pass makes no progress and returns
Args:
library_path: .PcbLib to fix; defaults to the focused library.
dry_run: report the plan without writing (default True).
fix_layer: move designators off the convention layer onto it.
fix_center: re-centre designators beyond the library's tolerance.
fix_height: also normalise text height to the library norm.
add_missing: create a Returns |
| lib_update_footprint_heights_from_3dA | Sweep the active PCB Library: for every footprint, find the
tallest 3D body and write its Footprint.Height is what Altium's placement-collision DRC uses to enforce height-clearance rules (don't place a tall electrolytic under a low overhang; don't sandwich an LCD connector under another PCB in a multi-board stack-up). Libraries shipped from vendors without explicit heights default to 0 which makes the DRC silently no-op -- a real production risk caught only at first-article assembly. Args:
mode: Reach for Safety:
Returns:
Dict with |
| lib_set_footprint_heightA | Set one footprint's Height directly, up or down. The sweep can only derive a height from a 3D body, which leaves two cases it cannot serve: a part with no model, and a part whose model is wrong. There was no setter at all before this, so a footprint carrying an absurd height could be read and not corrected. WHY TOO TALL IS WORSE THAN TOO SHORT. Footprint.Height drives placement-collision DRC. A footprint claiming 50mm when the part is 3mm fails against everything near it and blocks placements that are fine. A too-low height only fails to catch a real collision. The first floods the report and gets the rule switched off; the second is quiet. ZERO IS ACCEPTED AND IS NOT NEUTRAL. It disables the rule for that footprint rather than relaxing it, so nothing is ever flagged against it however tall the real part is. The reply says so when zero is written. Args: height_mm: the height in MILLIMETRES, not mils. Must be non-negative. footprint_name: which footprint. Empty uses the library's current component. Returns:
|
| lib_link_footprintA | Link a footprint to a schematic component. With replace=True (the default) any existing footprint (PCBLIB) model on the component is removed first, so re-linking replaces rather than appends. Pass replace=False to keep prior footprint models and add another (the old append behaviour, which bloats a component with duplicate models). Args: component_name: Name of the schematic component. Resolved by library reference and made current before linking, so the model lands on the symbol you name rather than on whatever was last created. Leave empty to target the current component. footprint_name: Name of the footprint to link footprint_library: NOT APPLIED, accepted only so existing callers keep working. The footprint is bound by NAME via the implementation's datafile link, with a deliberately EMPTY location: passing a .PcbLib path there wedges AD26 (see Lib_LinkFootprint in Library.pas). Install the library and keep footprint names unambiguous instead. replace: remove existing footprint models before adding (default True) Returns: Dictionary confirming link |
| lib_link_3d_modelA | Link a 3D STEP model to a PcbLib footprint. Loads the STEP geometry into the footprint as an IPCB_ComponentBody
(the real 3D body that drives the 3D view and the height/placement
DRC), so the active document must be the .PcbLib that contains the
footprint. Args:
component_name: Name of the footprint in the active PcbLib
model_path: Path to the 3D model file (.step, .stp); must exist
offset_x: X offset in mils from the FOOTPRINT's origin. The
body is always moved onto that origin first: it arrives
at the board origin, and a footprint open in the editor
sits at Altium's library origin, about 50000,50000 mil,
so an offset of 50000 used to be needed to bring it back.
Do not add that any more.
offset_y: Y offset in mils, applied with offset_x
offset_z: Z offset in mils, sets the body's StandoffHeight.
This is the common adjustment: lifting a connector body
off the board so it sits on its pads rather than through
them.
rotation_x: NOT APPLIED, accepted for signature stability.
Set it in the library editor after linking.
rotation_y: NOT APPLIED, same reason as rotation_x.
rotation_z: NOT APPLIED. This one used to assign
Returns:
Dict with |
| lib_auto_link_3d_modelsA | Batch-link STEP models to footprints by matching file names. Enumerates every footprint in the PcbLib, scans Args: model_dir: Folder containing .step/.stp model files. library_path: Optional .PcbLib to focus first; uses the focused document otherwise. Returns: {"linked": [{footprint, model}], "unmatched_footprints": [...], "unused_models": [...]}. |
| lib_get_componentsA | Get all components in a library. Default fast path returns only the metadata that the
Setting Setting Args: library_path: Path to library (uses active library if not specified) with_parameters: If True, include each component's parameter dict (slow on large libraries). Default False. with_designator: If True, include each component's default designator string (slow on large libraries; smaller payload than with_parameters). Default False.
Returns:
Dictionary with |
| lib_searchA | Search open SchLib documents and installed database libraries. OPEN .SchLib FILES AND INSTALLED DATABASE LIBRARIES (DbLib) ARE
SEARCHED. Query libraries (SVN DbLib), integrated libraries
(IntLib), workspace components and installed .SchLib files that
are not open are not, so 0 hits is not "no such part". The reply
says what was searched ( DbLib rows join Case-insensitive substring match. Walks every .SchLib that is
a member of any open project, plus every standalone .SchLib in
the workspace's free-documents area. Each library is read via
IT READS THE FILE ON DISK, NOT THE EDITOR. A component created
in this session and not yet saved WILL NOT BE FOUND, and the
reply is an ordinary empty result with nothing to say why.
MEASURED: a symbol that DATASHEET DISCIPLINE: Matches carry Args:
query: Substring to match against component name / alias /
description (case-insensitive).
search_type: Returns:
Dict with |
| lib_dblib_infoA | What a database library (.DbLib) declares, and how it connects. A DbLib holds no symbols. It names a database (Access, Excel, SQL
Server, any ODBC or OLE DB source) and lists the tables whose rows
are the components; each row names a symbol in a .SchLib and
footprints in .PcbLibs. This reads the .DbLib file itself, inside
Altium, and with THE PASSWORD IS NEVER RETURNED. HOW EACH COLUMN WAS FOUND IS STATED. Args: library_path: Full path of the .DbLib (or .SVNDbLib) file. lib_get_installed_libraries lists installed ones with library_type "database". with_fields: True (default) connects to the database to list every table's columns. False reads the file only and opens no connection: use it when the database is slow or unreachable, or to read the connection settings alone. Returns: {"library_path", "connection": {"provider", "kind" (access / excel / sql_server / odbc / oracle / other), "data_source", "has_password", "redacted", "read_only"}, "left_quote", "right_quote", "search_path", "table_count", "tables": [{"name", "enabled", "schema", "key_field", "key_field_source", "key_field_found", "symbol_ref_field", "symbol_library_field", "description_field", "footprint_fields": [{"ref_field", "library_field"}], "fields" (null when not read), "field_count", "error", "settings"}], "sections", "fields_included", "connected" (null when no connection was attempted)}. |
| lib_dblib_searchA | Search database libraries (.DbLib) for components, read-only. Case-insensitive substring match against the columns of every row of every enabled table, in one DbLib or in every installed one. lib_search already folds DbLib rows into its own results; this is the direct form, for restricting to one table or a few columns, or for raising the row bound on a large database. THE QUERY NEVER REACHES THE DATABASE. Each table is read with a
plain SELECT of the DbLib's own declared table and every row is
matched inside Altium, so a query holding quotes, wildcards or
SQL is matched as the text it is. The cost is that every row is
read: Args:
query: Text to find (case-insensitive substring).
library_path: One .DbLib to search. Omitted, every installed
database library is searched.
table: One table the DbLib declares (as lib_dblib_info names
it). Omitted, every enabled table.
fields: Column names to match. Omitted, every column. A name
a table lacks is reported under Returns:
{"query", "count", "limit", "truncated", "rows_scanned",
"scan_capped", "libraries": [{"library_path", "searched",
"error", "tables_searched", "tables_failed", "unknown_fields"}],
"results": [{"library_path", "table", "key", "key_field",
"symbol_ref", "symbol_library", "footprints": [{"ref",
"library"}], "description", "matched_field", "matched_value"}]}.
A library's |
| lib_dblib_get_recordA | Every column of one row of a database library table. The row is found by its key, the value in the table's key column
( Args: library_path: Full path of the .DbLib file. table: A table the DbLib declares. key: The row's key value. key_field: Optional column to match instead of the DbLib's own key column; it must be a column of the table. Returns:
{"library_path", "table", "key", "key_field",
"key_field_source", "lookup", "found", "match_count",
"rows_scanned", "scan_capped", "symbol_ref", "symbol_library",
"footprints": [{"ref", "library"}], "description",
"fields": {column: value}}. |
| sch_place_dblib_componentA | Place one database library (DbLib) part on a schematic sheet. Acts on a .SchDoc: the active sheet, or THE DbLib MUST BE AVAILABLE TO ALTIUM. Altium finds a DbLib part
by the library's file name among its available libraries, so the
DbLib has to be installed (lib_install_library) or in the
project. The call refuses before touching the sheet when it is
not, or when
Do not draw a schematic part by part with this. A sheet comes from a DesignPlan through design_execute_plan; this is for adding a part a person picked from their company library. Args:
library_path: Full path of the .DbLib file.
table: A table the DbLib declares.
key: The row's key value ( Returns:
{"placed", "library_path", "table", "key", "lib_reference",
"database_table", "database_linked", "x", "y", "rotation",
"part_id", "part_count", "part_id_applied", "designator"}.
|
| lib_get_component_detailsA | Get full inspection of one library component in a single call. Returns metadata, every pin, every parameter (as a flat dict),
AND visual-style records for the designator, comment, pins,
and each parameter (font_id, color, is_hidden, x, y,
orientation, justification). The integer If DATASHEET DISCIPLINE: This response is the highest-density
device-fact surface in the library API (pins, parameters,
Manufacturer/MPN). Treat every value as a hint to find the
manufacturer datasheet, not as ground truth. The response
carries Args:
component_name: Component LibRef as it appears in the .SchLib.
library_path: Optional .SchLib full path. When omitted the
currently focused library is used.
component_index: Alternative to component_name. The integer
Returns:
Dict with:
- name, library_path, description, alias_name,
part_count, pin_count
- designator: {text, font_id, color, is_hidden, x, y,
orientation, justification} - the on-canvas designator
label (NOT just the prefix string).
- comment: {text, font_id, color, is_hidden, x, y,
orientation, justification} - the on-canvas comment /
value label.
- pins: list of {designator, name, electrical_type, x, y,
orientation, hidden, label_hidden}. Pin font / color
are not exposed by the Altium SDK on ISch_Pin and
therefore not surfaced here.
- parameters: flat dict of name -> value (cheap lookups).
- parameter_styles: list of {name, value, style:{font_id,
color, is_hidden, x, y, orientation, justification}}
in the same order parameters appear on the symbol.
- models: list of the component's implementations (footprint
/ SPICE / 3D links), each {model_name, model_type,
is_current, datafile_links:[{entity_name, file_kind,
location}]}. datafile_links is the model's source (the
library it resolves from); empty when the footprint binds
by name only. Empty list when the part carries no models.
- |
| lib_audit_stylesA | Bulk visual-style audit across every component in a library. Walks the focused .SchLib (or one specified by Filter mode: pass
Args: library_path: .SchLib path. Defaults to focused doc. with_comment: Include comment style record per component. with_parameters: Include parameter_styles array per component. with_pins: Include pins array per component. expect_designator_font_id: Filter; trim components where designator.font_id equals this value. expect_designator_color: Filter; trim components where designator.color equals this BGR int (e.g. 8388608 for navy / 0x000080 in BGR-packed form). limit: Cap on emitted entries. Default 5000. timeout: Per-call bridge poll timeout override (seconds). Returns: Dict with library_path, count (emitted), mismatch_count (subset that failed the filter), limit, truncated, filter_applied, and components: list of {name, designator:{...}, mismatched, comment?:{...}, pins?:[...], parameter_styles?:[...]}. |
| lib_set_label_formatsA | Multi-target label-style writer for SchLib symbols. Applies SEVERAL label target/style ops to SchLib symbols in one IPC round-trip (there is no singular variant). The library is opened once and walked once; every op is applied to each component in turn. Five sequential per-target writes would collapse into one trip plus one library walk -- which is the dominant cost on large libraries (each individual call runs an IPC, a workspace lookup, a doc-focus check and a CompInfoReader walk). Each At least one style field must be set per op. Targets are
Args:
ops: List of per-target style ops. Must be non-empty.
Targets may not contain the wire separators Returns:
Dict with library_path, scope ("single"|"bulk"),
total, limit, truncated, and an |
| lib_set_mech_layersA | Name, enable and kind the mechanical layers of one library. WHY THIS EXISTS RATHER THAN THE pcb_* LAYER TOOLS. Those act on whichever board is current, and pointing them at a particular library depends on the focus actually moving. When it does not they operate on the previously focused library while reporting success: a sweep over twenty one libraries returned twenty one identical answers because every call had re-read the same file. This takes the library by PATH and refuses unless the document that ended up focused is the one asked for. Acting on the wrong library is worse than not acting, because it looks like it worked. Every change is READ BACK. A layer whose name, enable or kind did not take is reported against that layer rather than folded into an overall pass. PAIRED KINDS. Any kind ending in Top or Bottom is held by the
layer PAIR rather than by either layer, under a shorter name with
the side dropped, so "Courtyard Top" is stored as the pair kind
"Courtyard". Assigning one therefore needs BOTH sides in the same
call: give the partner kind to another layer in Pair with Args:
layers: One dict per layer. Keys: Returns:
Dict with |
| lib_run_acrossA | Run one library command against several libraries in one call. Sweeping libraries one at a time costs a round trip and a turn of orchestration per library. This sends the whole sweep as a single request and loops inside Altium. WHAT THIS DOES NOT SAVE. Opening and saving each library, which is the larger cost and is unavoidable. The saving is the round trips and the waiting between them, which is what makes a twenty library sweep tedious rather than slow. WHICH ACTIONS WORK. Those that accept a FAILURE IS PER LIBRARY. One library that will not open does not abandon the rest, and the reply reports each library separately rather than as a single flag. "17 of 20 worked" collapses into either a false clean or a false failure the moment it becomes one boolean, and the caller cannot tell which library to fix. Args:
action: Library command without its namespace, e.g.
"get_components", "batch_rename", "audit_styles".
libraries: Full paths. Passed to Altium separated by "|",
which cannot occur in a Windows path.
params: Parameters shared by every library. Any
Returns:
Dict with |
| lib_batch_set_paramsA | Batch set parameters on library components. Each assignment sets one parameter on one component. If the parameter exists it is updated; if not it is created. Two
Args: assignments: List of dicts with keys: - component_name: Name of the component in the library - param_name: Parameter name (e.g., "Partnumber", "Manufacturer"), or the special "Description" / "Designator" property keys - param_value: Value to set library_path: Path to library (uses active library if not specified) Returns: Dictionary with counts of updated, created, and failed assignments |
| lib_batch_renameB | Batch rename components in a schematic library. Each assignment renames one component from old_name to new_name. Args: assignments: List of dicts with keys: - old_name: Current name of the component in the library - new_name: New name for the component library_path: Path to library (uses active library if not specified) Returns: Dictionary with counts of renamed and failed assignments |
| lib_diff_librariesA | Compare two schematic libraries and report differences. Returns which components are only in library A, only in B, or shared. Args: library_a: Full path to the first SchLib file library_b: Full path to the second SchLib file Returns: Dictionary with only_in_a, only_in_b, common arrays, and count_a, count_b, only_a, only_b, shared counts |
| lib_add_symbol_arcA | Add an arc to the current library symbol. Args: x_center: Center X coordinate in mils y_center: Center Y coordinate in mils radius: Arc radius in mils start_angle: Start angle in degrees (0 = right, 90 = up) end_angle: End angle in degrees width: Line width (0=zero, 1=small, 2=medium, 3=large) grid: snap grid (mils); arcs are glyph detail and don't need the 100-mil pin grid (rule 15), so the default is a finer 25 (e.g. inductor coils). Pass 100 for coarse, 0/1 for none. Returns: Dictionary confirming arc addition |
| lib_add_symbol_polygonA | Add a polygon (filled shape) to the current library symbol. Args: vertices: Comma-separated x,y coordinate pairs in mils. Example: "0,0,100,0,100,100,0,100" creates a square with vertices at (0,0), (100,0), (100,100), (0,100). Minimum 3 vertices (6 values) required. grid: snap grid (mils) for the vertices. A filled polygon is glyph detail (e.g. a diode triangle) and doesn't need the 100-mil pin grid (rule 15), so the default is a finer 25; pass 100 for coarse or 0/1 to disable snapping. Returns: Dictionary confirming polygon addition with vertex count |
| lib_set_component_descriptionC | Set the description field on a library component. Args: component_name: Name of the component in the active library description: New description text Returns: Dictionary confirming the description was set |
| lib_get_pin_listA | Get all pins of a library component. NAME THE COMPONENT. Without DATASHEET DISCIPLINE: Pin name + electrical_type from the
symbol can be wrong, especially on libraries that have been
edited by hand or imported from third-party sources. Before
relying on a pin's function for any decision, fetch the
manufacturer datasheet and verify against its pin-description
table. The response carries BIG SYMBOLS SPILL TO A FILE ON PURPOSE. A 699-pin module returns
more than a conversation can hold, and which half survives is
then decided by whichever client happens to be reading. Above
Args: component_name: library reference of the symbol to read. Empty falls back to the editor's current component. output_path: write the full pin array here as JSON and return the summary. Forces the file path regardless of size. inline_limit: pin count above which the array is written to a file instead of returned inline. 0 always returns inline, which is what you want only for a small symbol. Returns:
Dictionary with "count", "component" name, and "pins" array.
Each pin has: designator, name, electrical_type, x, y,
orientation, hidden. Plus |
| lib_set_pin_owner_partA | Reassign pins of a multi-part symbol to a sub-part, or to Part Zero.
Changes the library only. Placed instances pick it up on the next Update From Libraries, which produces an ECO. Args: pin_designators: comma-separated pin numbers, e.g. "3,12". owner_part_id: 0 for Part Zero, or 1..part_count. component_name: library reference of the symbol to edit. Empty falls back to the editor's current component. Returns: Dictionary with "component", "owner_part_id", the "pins_changed" list and its "count". |
| lib_export_kicad_symbolA | Export a SchLib symbol to a KiCad .kicad_sym file. Reads the symbol's pins from the active schematic library and writes a KiCad 6+ S-expression symbol: a body rectangle sized to the pin roots plus one pin per Altium pin (designator -> number, name, electrical type, position, orientation). Coordinates convert mils -> mm. This covers the symbol only; footprint export is separate. Naming a component SELECTS it in the library, and that outlives
the call: exporting is a read, but it leaves the library on the
component it exported. Tools called afterwards without a
component name act on whatever is current, so a following
Args: component_name: LibRef to export. If empty, exports whatever component is currently selected in the SchLib. output_path: Destination .kicad_sym file. Defaults to workspace/.kicad_sym. reference: Reference designator prefix for the symbol (default "U"). Returns: {"output_path", "symbol", "pin_count"} or an error. |
| lib_export_kicad_footprintA | Export a PcbLib footprint to a KiCad Reads the footprint's pads from the active (or named) PCB library and
writes a KiCad 6+ S-expression footprint: one pad each
(designator -> number, position, size, shape, drill, layer set).
Through-hole pads (hole > 0) get a drill and the all-copper layer set;
SMD pads get the side's Cu/Paste/Mask set. Altium mils convert to mm
and the y axis is flipped (Altium y-up -> KiCad y-down). This is the
footprint counterpart to Args: footprint_name: Footprint to export. If empty, exports the library's current footprint. output_path: Destination .kicad_mod file. Defaults to workspace/.kicad_mod. Returns: {"output_path", "footprint", "pad_count"} or an error. |
| lib_copy_componentA | Copy a component WITHIN or BETWEEN schematic libraries. Replicates the source component (all pins, graphics, parameters)
and adds it to the destination library. When Args:
source_name: lib_ref of the component to copy.
new_name: lib_ref for the clone. Defaults to Returns:
Dictionary with |
| lib_copy_footprintA | Copy one footprint (all pads/primitives) into a PcbLib, optionally renaming. Footprint analog of lib_copy_component: full-copies the footprint with no delete. source_library defaults to the focused PcbLib; dest_library defaults to the source. A same-library copy requires a different new_name. Errors if new_name already exists in dest unless overwrite. Args: source_name: the footprint to copy. new_name: name for the copy (default source_name). source_library: source .PcbLib path (default the focused lib). dest_library: destination .PcbLib path (default source). overwrite: replace a same-named footprint already in dest. Returns: {"success": true, "source": "...", "new_name": "...", "same_library": bool}. |
| lib_move_componentsA | Move matching components (symbol + params + models) between SchLibs. Bulk analog of lib_copy_component: copies every matching component from source_schlib to dest_schlib (Replicate carries the whole symbol, its parameters and its models) in one pass, then removes them from source unless delete_from_source is False. This is the piece that makes a full library split a single call. Provide either names (explicit LibReferences) or name_regex (matched against the source's component names). With names it is one IPC call; with name_regex the source component list is fetched first to resolve the matches, then the move runs. A component already present in dest is skipped unless overwrite=True. Args:
source_schlib: source .SchLib path.
dest_schlib: destination .SchLib path.
names: explicit list of component LibReferences to move.
name_regex: regex matched against source component names when names
is not given.
delete_from_source: remove moved components from source (default True).
overwrite: replace a same-named component already in dest.
dry_run: resolve the selection and report it WITHOUT moving
anything. Worth doing whenever name_regex is used: the
pattern is applied with Returns: {"success": true, "moved": N, "skipped": N, "failed": N}, or in dry-run {"dry_run", "resolved", "count", ...} with nothing sent to the bridge. A failed copy does not delete: the handler counts it in |
| lib_move_footprintsA | Move matching footprints between PcbLibs (the PcbLib analog of move). Copies every matching footprint (all pads and primitives, via a full copy) from source_pcblib to dest_pcblib, then removes them from source unless delete_from_source is False. The footprint counterpart of lib_move_components; together they split a full library. Provide either names (explicit footprint names) or name_regex (matched against the source's footprint names). With names it is one IPC call; with name_regex the source footprint list is fetched first. A footprint already present in dest is skipped unless overwrite=True. Args:
source_pcblib: source .PcbLib path.
dest_pcblib: destination .PcbLib path.
names: explicit list of footprint names to move.
name_regex: regex matched against source footprint names when names
is not given.
delete_from_source: remove moved footprints from source (default True).
overwrite: replace a same-named footprint already in dest.
dry_run: resolve the selection and report it WITHOUT moving
anything. Worth doing whenever name_regex is used: the
pattern is applied with Returns: {"success": true, "moved": N, "skipped": N, "failed": N}, or in dry-run {"dry_run", "resolved", "count", ...} with nothing sent to the bridge. |
| lib_split_pin_functionsA | Split slash-delimited pin names into pin function lists. For the current library symbol, parses each pin whose name is
Returns: {"pins_processed": N}. |
| lib_get_installed_librariesA | List the libraries installed in the Altium environment. The answer to "what libraries does this installation have?", which
no other tool gives: INSTALLED IS NOT AVAILABLE. Installed libraries are the ones switched on for this environment; available ones are every library it knows about. This returns the installed list and reports the available total beside it, so a library that is present but not switched on shows up as a gap between the two numbers rather than as an absence. Args: with_counts: True (default) also reports how many components each library holds. That opens every library to count them, so pass False for a fast listing; the count then comes back as -1, meaning not asked rather than empty. Returns:
{"libraries": [{"library_path", "file_name", "library_type",
"library_type_ordinal", "component_count"}], "installed_count",
"available_count", "counts_included"}. |
| lib_install_libraryA | Register a library with the environment's Available Libraries. Installs an .IntLib / .SchLib / .PcbLib so its parts resolve by lib-ref across the workspace (the step after authoring a library). Args: library_path: absolute path to the library file. Returns: {"installed": bool, "library_path": "..."}. |
| lib_get_vault_nameA | The Workspace name the managed tools would use, read off the design. Altium writes the Workspace name onto every managed part it
places. This reads it from the active sheet, then from the other
sheets that are already open; it never opens one. A Workspace has
been seen under two names on one design, so a part addressed by
kind 4 (VaultName) is preferred and Returns:
|
| lib_find_vault_componentsA | Find the Design Item ID of a managed part by its exact name. Looks through the managed (Workspace) parts already placed on the
sheets Altium has open, and matches It does not search the whole Workspace: that needs Altium's EDMS interfaces, whose methods no reference documents, and a call this Altium lacks would stop the bridge. A part not yet used in the design has to be looked up in Altium's Components panel. Args: name: The comment, library reference or Design Item ID. Returns:
|
| lib_get_vault_componentA | Check one managed (Workspace) component can be placed, without placing it. Loads the item the way Args:
design_item_id: The component's Design Item ID.
vault: The Workspace name. Usually left out; see
Returns:
|
| lib_uninstall_libraryB | Unregister a library from the environment's Available Libraries. Args: library_path: absolute path to the library file. Returns: {"uninstalled": bool, "library_path": "..."}. |
| lib_delete_componentA | Delete one symbol from a schematic library (.SchLib). Removes the component whose LibReference is Args:
component_name: the component's LibReference (its library name).
library_path: optional absolute .SchLib path to target; defaults
to the currently focused library document.
component_index: alternative to component_name; the integer
Returns: {"success": true, "library_path": "...", "deleted": "..."}. |
| lib_rename_componentA | Rename one symbol's LibReference in a schematic library (.SchLib). This is the repair path for a component whose current name carries
bytes a caller cannot reproduce (an embedded double-quote, or a
control char left by a broken import). Address it by
The component is removed and re-added under the new name so the
library's internal by-name index is rebuilt. Errors with
NAME_EXISTS if a different component already uses Args:
new_name: the clean LibReference to write.
component_name: current LibReference of the target. Provide this
or component_index.
library_path: optional absolute .SchLib path; defaults to the
focused library.
component_index: the integer Returns: {"success": true, "library_path": "...", "old_name": "...", "new_name": "..."}. |
| lib_delete_footprint_primitivesA | Delete primitives inside ONE footprint of a PCB library. THE ONLY LIBRARY-SCOPED PRIMITIVE DELETE. SCOPED THREE WAYS, all of which must agree before anything is removed: the library by path, the footprint by name, and the object type or layer. The library is verified AFTER it is brought to the front, so a delete aimed at one that never focused is refused rather than landing in whichever did. PADS ARE EXCLUDED unless THE FOOTPRINT ON SCREEN IS EDITED FROM ANOTHER. The footprint the
editor shows keeps its primitives on the library board, which is
written back into it at the next switch, so removing from it in
place came undone. When the target is on screen, another
footprint is made current for the delete (a temporary one in a
single-footprint library, removed afterwards) and the target is
shown again at the end; Args:
footprint_name: The footprint to edit. Required: deleting
from whichever footprint the editor happens to show is
the mistake this avoids.
object_type: PCB object type, e.g. "track", "arc", "text",
"region", "fill". Give this or Returns:
Dict with |
| lib_move_bodies_to_layerA | Put the 3D bodies of the focused PCB library on one mechanical layer. Libraries put together from several sources carry their bodies on whatever layer each source used, so one footprint's model shows with a layer turned on and the next one's never does. Every footprint, or only the named ones, has each body moved; a body already on the layer is counted and left alone. Nothing is added or removed. Args:
layer: The mechanical layer, by number ("Mechanical13") or by
the name the library's stack gives it. Anything else is
refused, as Altium's body dialog only offers mechanical
layers.
footprint_names: Only these footprints. Empty means every
footprint in the library; names no footprint has come
back in Does NOT save the library. A mechanical layer the library has not
enabled is accepted, with Returns:
Dict with |
| lib_redraw_assemblyA | Draw the assembly layer of the focused PCB library again from
each footprint's own geometry: a rectangle round the part and a
Libraries collected over the years carry the assembly drawing on
the wrong layer, from another package, or not at all. With
Args:
layer: The mechanical layer the assembly drawing goes on.
footprint_names: Only these footprints. Empty means all.
outline_from: What the rectangle goes round. The footprint on screen is shown again at the end. Does NOT save
the library. A mechanical layer the library has not enabled is
accepted, with Returns:
Dict with |
| lib_delete_footprintA | Delete one footprint from a PCB library (.PcbLib). Finds the footprint by name, removes and deregisters it, and MARKS
the .PcbLib dirty. It does NOT write to disk: this bridge defers
saves, and Deletes a single named footprint; if the name is not found the call errors (FOOTPRINT_NOT_FOUND). No wildcard mass-delete. Args: footprint_name: the footprint's name in the library. library_path: optional absolute .PcbLib path to target; defaults to the currently focused library document. Returns: {"success": true, "library_path": "...", "deleted": "..."}. |
| lib_set_model_nameA | Set a model's model_name (footprint reference) on a SchLib symbol. Rewrites the ModelName of one of the component's implementations. If model_name is given, the model whose current ModelName matches is targeted; otherwise the current (or first) model is used. Args: component_name: the component's LibReference. new_model_name: the new model_name to write. model_name: optional current model_name to target a specific one. library_path: optional .SchLib path; defaults to the focused lib. Returns: {"success": true, "component": "...", "new_model_name": "..."}. |
| lib_set_model_sourceA | Write the datafile-link Location (source library) on a footprint model. A footprint whose datafile link has an empty Location resolves in the SchLib editor by name but cannot embed into a self-contained compiled library, so the footprint goes missing in the used/compiled output even though the package's own compile reports no error. This writes Location so the model is embeddable. Location is set in place (never through AddDataFileLink with a path, which wedges AD26). Targets PCBLIB models matching model_name, or all PCBLIB models when it is empty. IMPORTANT: get the exact source_library string from a known-good model that already embeds correctly. Read it via lib_get_component_details, whose models array now shows each model's location and use_component_library. This tool writes exactly what you pass; it does not infer the format. Args: component_name: the component's LibReference. source_library: the source-library reference written into Location. model_name: optional footprint model name to target one model. use_component_library: optional; sets the embed-vs-search flag. library_path: optional .SchLib path; defaults to the focused lib. Returns: {"success": true, "component": "...", "source_library": "...", "models_updated": N}. |
| lib_remove_modelA | Remove models (implementations) from a SchLib component by name. Removes every implementation whose ModelName equals model_name. With keep_one=True it keeps the first match and removes the rest, which deletes duplicate model links while preserving one. Errors if the component is not found; returns removed=0 if no model matches. Args: component_name: the component's LibReference. model_name: the ModelName of the model(s) to remove. keep_one: keep the first match and remove the rest (dedup). library_path: optional .SchLib path; defaults to the focused lib. Returns: {"success": true, "model_name": "...", "removed": N, "kept_one": bool}. |
| lib_rename_footprintA | Rename a footprint in a PCB library (.PcbLib). Renames the footprint whose name is footprint_name to new_name. Errors if footprint_name is not found or new_name already exists in the library. MARKS the .PcbLib dirty; it does not write. Call Args: footprint_name: the current footprint name. new_name: the new footprint name. library_path: optional .PcbLib path; defaults to the focused lib. Returns: {"success": true, "footprint": "...", "new_name": "..."}. |
| lib_probe_footprintA | Read-only dump of a PcbLib footprint's name-bearing fields. Use this to locate where an old name persists after a rename. On a PcbLib footprint, Name and Pattern are the SAME property (renaming Name writes both), and the footprint's only metadata is Name, Description, Height. So a leftover old name lives in a child primitive: this returns every text primitive's object_id and text, plus name/description/ height_mils/primitive_count. Nothing is written. Args: footprint_name: the footprint name. library_path: optional .PcbLib path; defaults to the focused lib. Returns: {"success": true, "footprint": "...", "description": "...", "height_mils": N, "primitive_count": N, "texts": [{"object_id": N, "text": "..."}]}. |
| lib_get_pad_geometryA | Full-precision pad geometry of one PcbLib footprint, in mm. The measurement half of the datasheet land-pattern audit. Unlike the integer-mil dump behind lib_audit_footprint_policies, every dimension here is a float in millimetres (a 0.65 mm pitch loses 10 um to integer-mil rounding, which a tolerance comparison against the datasheet cannot afford). Coordinates are relative to the footprint's own origin. Args: footprint_name: the footprint name in the library. library_path: optional .PcbLib path; defaults to the focused library. Returns: {name, description, library_path, pad_count, pads: [{ name, x_mm, y_mm, copper_x_mm, copper_y_mm, w_mm, h_mm, shape, corner_pct, rotation, hole_rotation, hole_mm, hole_w_mm, hole_type, slot_aligned (slots only), plated, layer, paste_expansion_mm, paste_expansion_source, paste_expansion_state, mask_expansion_mm, mask_bottom_expansion_mm, mask_separate, mask_expansion_source, mask_expansion_state}]}. mask_expansion_mm is the TOP side when mask_separate is true and both sides when it is false; mask_bottom_expansion_mm is the stored bottom value, which takes effect once the sides are unlinked even while it is not in use. x_mm/y_mm are the pad's origin; copper_x_mm/copper_y_mm are the centre of its copper, which differs on a custom pad. hole_rotation is relative to the pad, so a slot lines up when the copper's and the hole's long axes agree in the pad's frame, which slot_aligned reports. *_expansion_source is 'manual' when the pad overrides the design rule, 'rule' otherwise (value 0 in that case: the rule's value lives in the design rules, not on the pad); *_expansion_state is the cache's own manual, valid or invalid. |
| lib_set_pad_propertiesA | Change pads that already exist in a PcbLib footprint. Every pad named A mask or paste expansion is written with the pad's manual flag
set: without it Altium ignores the value and follows the board's
rule, and a library has no rules. THE MASK HAS TWO SIDES. A pad keeps a top and a bottom solder
mask expansion; with the sides linked the top value serves both,
but the bottom value is still stored and takes effect the moment
the sides are unlinked. So Args:
footprint_name: The footprint holding the pad.
pad_name: The pad's designator.
library_path: Optional .PcbLib path; defaults to the focused
library.
units: "mil" (default) or "mm", for every length here.
x_size, y_size: Copper size.
shape: "round", "rectangular" or "octagonal".
rotation: Pad rotation in degrees.
hole_size: Hole diameter, 0 for a surface-mount pad.
hole_width: Slot length; makes the hole a slot.
hole_rotation: Slot rotation relative to the pad, in degrees.
plated: Whether the hole is plated.
paste_expansion, mask_expansion: Expansions, set as manual.
Returns:
|
| lib_get_footprint_primitivesA | Every non-pad primitive of one PcbLib footprint, with where it is. Tracks, arcs, regions, fills, texts and vias, each with its layer
(the name the library's stack gives it, plus Args: footprint_name: The footprint name in the library. library_path: Optional .PcbLib path; defaults to the focused library. Returns: {name, library_path, height_mm, bodies (a count), body_layers (the layer of each body), tracks [{layer, layer_id, x1, y1, x2, y2, width}], arcs [{layer, layer_id, xc, yc, r, start, end, width}], regions and fills [{layer, layer_id, x1, y1, x2, y2, area (regions)}], texts [{text, layer, layer_id, x, y, size, rotation, x1, y1, x2, y2}], vias [{x, y, diameter, hole}]}. A text's box is Altium's cached one and can lag an edit made this session. |
| lib_audit_footprint_vs_datasheetA | Audit a footprint against the manufacturer's land pattern. Deterministic comparison of the REAL pad geometry (read live from the .PcbLib) against a land-pattern spec transcribed from the manufacturer datasheet: pad count, every pad's position / size / shape / drill, the numbering sequence, pitch (implied by positions), the thermal pad, and its paste policy. Alignment is automatic (centroid + best of the four 90-degree rotations), so library origin and rotation conventions do not produce false errors; a MIRRORED pattern is deliberately not compensated and reports as position/sequence errors. DATASHEET DISCIPLINE: the spec must be transcribed from the
manufacturer datasheet fetched in this conversation, and
The spec (JSON object or string): source: {datasheet_url, reference, part_number} REQUIRED pads: [{name, x, y, w, h, shape?, hole?}] explicit, mm dual_row: {count, pitch, span, pad_w, pad_h, shape?} quad: {count, pitch, span_x, span_y, pad_w, pad_h, shape?} thermal_pad: {name, x, y, w, h, shape?} thermal_paste: 'full' | 'windowed' position_tol / size_tol: mm, default 0.05 dual_row expands with the SOIC/SOP convention (pin 1 top-left,
CCW); quad with the QFP/QFN convention (pin 1 top of left side,
CCW). For any other numbering give explicit Returns: {ok, rotation_applied_deg, findings: [{check, severity, message, pad?, expected?, actual?}]} plus the footprint geometry under 'footprint' for reference. ok is true only with zero error-severity findings. |
| lib_audit_footprint_vs_packageA | Audit an existing PcbLib footprint against its package drawing. Where lib_audit_footprint_vs_datasheet compares pads with a land pattern typed in, this takes the PACKAGE (the same PackageSpec as lib_create_footprint_from_package) and checks the footprint is right for it. Reads only. Checked: pad count, numbering and pin 1 (a mirror-image footprint,
the bottom-view mistake, is named as such); pitch exactly; row
span, land sizes and land centres against the IPC-7351B pattern
within the deviations measured between real vendor patterns and
IPC (a footprint drawn to the vendor's own pattern passes); every
land covering the centre of its terminal; holes against the leads;
paste on an exposed pad (closed opening plus windows covering 50
to 80 %) and on every land; manual solder mask settings; origin at
the package centroid; and, from the footprint's other primitives,
a courtyard that encloses the lands and the body, silkscreen off
the copper, an assembly outline that follows the body, and the
footprint height against the package's maximum. A turned footprint
is compared after turning it back. What could not be read is
listed under Run footprint_check_package on the package first: an audit against a misread package passes a footprint built from the same misread. Args: footprint_name: the footprint in the library. package: the PackageSpec as an object or JSON text. density: L, N or M, the IPC pattern compared against. library_path: optional .PcbLib path; default the focused one. assembly_layer, courtyard_layer: the mechanical layers for those roles; empty picks them by the library's layer kind ("Assembly Top" / "Courtyard Top"), then by name. Returns:
|
| lib_easyeda_searchA | Search LCSC / EasyEDA for parts by MPN or description. EXPECT THIS TO FAIL, and NOT because of credentials. Checked against the live service: the search route answers 404/403 with an HTML error page and no auth challenge, component fetch on the SAME host still works with no credentials, LCSC's own search API returns an error body, and the LCSC results page is rendered client-side (fetching it yields zero part numbers). There is no endpoint left to log in to, so no cookie, token or account will restore this. Search is therefore a BROWSER task, which also keeps it per-user: each person searches LCSC in their own signed-in browser, and no shared credential is ever stored by this server. Take the part number from there and import by id, which is unaffected: lib_easyeda_import(lcsc_id="C1234", ...). Online. Returns candidates only, no geometry: pick an lcsc_id and pass it to lib_easyeda_import. HTTPS-only with a host allowlist; override endpoints with EASYEDA_API_BASE. Args: query: MPN, keyword, or description fragment. limit: max candidates (default 20). Returns: {"ok": true, "count": N, "results": [{lcsc_id, mpn, manufacturer, package, description}]}. |
| lib_kicad_importA | Convert a KiCad .kicad_sym / .kicad_mod into an Altium plan. Closes the gap that made KiCad-format part sources useless on
the Altium side: this server could export Altium to KiCad but
had no path back, so a hit from a KiCad registry or from the
local KiCad libraries (see Parses into the SAME neutral model the EasyEDA importer uses, so the Altium plan is produced by one shared emitter rather than a second copy that would drift from it. Give MULTI-PART COMPONENTS: a quad gate or dual op-amp converts in
ONE call to a real Altium multi-part symbol ( HIDDEN PINS: kept, and kept hidden. A hidden pin is electrically real (this is how symbols carry supply rails and no-connects), so dropping it would lose a pin while showing it would clutter the symbol. DERIVED SYMBOLS: over half of KiCad's standard entries carry no
geometry of their own and inherit it from a parent. That link is
followed, and target="altium": returns an ORDERED PLAN of this server's own library tools, exactly like lib_easyeda_import. Nothing is written to Altium; review the plan, then execute the steps. target="inspect": parse only, return a summary and warnings. Use this first on an unfamiliar library. DATASHEET DISCIPLINE: a converted footprint is somebody else's
drawing, not a verified land pattern. Audit it against the
manufacturer document with Returns:
|
| lib_easyeda_importA | Convert an EasyEDA / LCSC part to KiCad files or an Altium plan. Independent implementation from EasyEDA's published format spec, so symbol and footprint geometry, pads, drills, silkscreen and metadata all convert without any third-party converter. Source: target="kicad": writes target="altium": returns an ORDERED PLAN of this server's own
library tools (lib_create_symbol, lib_add_pins,
lib_create_footprint, lib_add_footprint_pads, lib_link_footprint,
...) that recreates the part in target="inspect": parse only, return the component summary and warnings. Use this first on an unfamiliar part. DATASHEET DISCIPLINE: an imported footprint is a vendor drawing,
not ground truth. Audit it with
Returns: {"ok": ..., "component": {...}, "warnings": [...]} plus "files" (kicad) or "steps"/"summary" (altium). |
| lib_clear_source_libraryA | Unpin a SchLib's symbols from their source-library provenance. Library-side sibling of Per matching component: clears SourceLibraryName, resets TargetFileName to '*', and syncs DesignItemId to the LibReference (each independently switchable). This is the minimal fast path of what lib_normalize_implementations does inside its full model sweep, when you only need the provenance cleaned, use this. Deferred save: flush with app_save_all. Args: library_path: absolute .SchLib path; empty = focused library. component_names: restrict to these LibReferences; None/empty = every component in the library. clear_target_file_name: reset TargetFileName to '*'. sync_design_item_id: set DesignItemId = LibReference where they differ. Returns: {"library_path": ..., "total": inspected, "cleared_source_library": n, "cleared_target_file_name": n, "synced_design_item_id": n}. |
| lib_normalize_implementationsA | Clean up every component's models in a SchLib for a self-contained package. Whole-library sweep. Per component it: clears the component-level provenance (SourceLibraryName, TargetFileName); collapses duplicate models, keeping ONE per (model_type, model_name) IN PLACE so the kept model's parameters, MapAsString pin-map, and datafile link are all preserved; re-flags the survivor current if any duplicate was; optionally renames a model's name and its datafile entity via rename_map; and repairs any footprint (PCBLIB) left with no datafile link. It does NOT destroy and rebuild implementations, so nothing on a model is lost. With source_library set, it also writes that value into the Location of every PCBLIB model's datafile link, turning a name-only library (footprints resolve but do not embed) into an embeddable one in the same pass. Existing Locations are only overwritten when source_library is given; they are never blanked. Get the exact string from a known-good model first (see lib_set_model_source). Note: it preserves what is present; it cannot resurrect data a prior broken run already dropped. If a library was damaged by an earlier version, restore the backup and run this on it. If you are also renaming footprint entities, run lib_rename_footprint on the PcbLib first, then pass the same {old: new} as rename_map so symbol and footprint stay matched. Args: library_path: optional .SchLib path; defaults to the focused lib. rename_map: optional {old_model_name: new_model_name} applied to the kept model's name and matching datafile entity. dedupe_only: skip renames; only collapse duplicates + clear source. source_library: optional; when set, written into every PCBLIB model's datafile Location so footprints embed on compile. use_component_library: optional; sets the embed-vs-search flag on the models whose Location is written. Returns: {"success": true, "components_touched": N, "duplicates_removed": N, "sources_cleared": N, "links_repaired": N, "sources_set": N}. |
| lib_inspect_cse_zipA | Identify the library members of a Component Search Engine zip. Stage 5 of the autonomous flow (library readiness,
reference/autonomy-roadmap.md): a SamacSys / Component Search
Engine download carries the symbol, footprint and 3D model for an
MPN in one zip. This tool reads the archive WITHOUT extracting
anything: which member is the .SchLib, which the .PcbLib, which
the STEP model, the best-effort MPN, and any members attempting
path traversal ( Args: zip_path: Absolute path to the downloaded zip. Returns:
|
| lib_extract_cse_zipA | Extract a Component Search Engine zip and build its install plan. Stage 5 of the autonomous flow (library readiness,
reference/autonomy-roadmap.md): stages the recognized members
(.SchLib / .PcbLib / STEP) flattened into Args:
zip_path: Absolute path to the downloaded zip.
dest_dir: Where to stage the files. Default:
Returns:
|
| obj_queryA | Query schematic OR PCB objects and read their properties. Iterates objects of the given type, optionally filtering by property values, and returns the requested properties for each matching object. Args: object_type: Altium object type constant. Schematic: "eNetLabel", "ePort", "ePowerObject", "eSchComponent", "eWire", "eBus", "eBusEntry", "eParameter", "ePin", "eLabel", "eLine", "eRectangle", "eSheetSymbol", "eSheetEntry", "eNoERC", "eJunction" PCB: "eTrackObject", "ePadObject", "eViaObject", "eComponentObject", "eArcObject", "eFillObject", "eTextObject", "eRuleObject", "eDimensionObject", "eConnectionObject" (the ratsnest: one line per unrouted connection, with X1, Y1, X2, Y2, Layer1, Layer2 and Net) properties: Comma-separated property names to return. Returns: Dictionary with "objects" array and "count" |
| obj_explain_pinA | Explain WHY a schematic pin is on the net it is on.
Reports the pin's ROOT ( Reading the result:
Hits are filtered by the object's Location (or a pin's electrical
end, or a wire vertex), not by bounding box. Altium's
Args: designator: Component designator, e.g. "U10". pin: Pin NUMBER (not pin name), e.g. "5". Returns:
Dict with |
| obj_modifyA | Apply ONE set of property values to every object matching ONE filter. IMPORTANT, if every target object needs a DIFFERENT value (move 10
pins to 10 different positions, rename 5 nets to 5 different names,
set distinct designators per component), use Use this tool when the SAME set string applies to every match (e.g., "set every 10k resistor's Tolerance to 1%"). Args:
object_type: Altium object type constant (see Returns: Dictionary with "matched" count and "sheets_processed" Example - rename a net across all sheets (one value fits all matches): obj_modify( object_type="eNetLabel", scope="project", filter="Text=OLD_NET", set="Text=NEW_NET" ) Example - modify a specific sheet without switching: obj_modify( object_type="eParameter", scope="doc:C:\path\MODULE_A.SchDoc", filter="Name=Title", set="Text=Module A" ) Example - edit a pin inside one SchLib symbol (no lib_set_current_component): obj_modify( object_type="ePin", scope="lib_component:R_0402", filter="Designator=1", set="Name=A" ) |
| obj_createA | Create and place a schematic object. If you are creating more than one object, use Args:
object_type: Altium object type constant (see Returns: Dictionary confirming creation |
| obj_deleteA | Find and delete schematic or PCB objects. For several scope/type/filter sets at once, use A PCB type (eTrackObject, eViaObject, ...) deletes from the active
board, and matches a footprint's own primitives and a polygon's
hatching too unless the filter says "InComponent=false" and
"InPolygon=false". To take up routing, Args:
object_type: Altium object type constant (see A filter that is not Name=Value pairs (an Altium query expression
such as Returns: Dictionary with "matched" count (number deleted) |
| obj_get_font_specA | Get font properties for a given font ID. Reads the Altium font table to retrieve the full font specification (size, name, bold, italic, etc.) for a font ID obtained from an object's FontId property. Args: font_id: Font ID from an object's FontId property Returns: Dictionary with font_id, size, rotation, bold, italic, underline, strikeout, font_name |
| obj_get_font_idA | Get or create a font ID for the given font properties. Looks up (or creates) an entry in the Altium font table matching the
specified properties and returns its font ID. Use the returned font_id
to set an object's FontId property via Args: size: Font size in points (e.g., 8, 10, 12) font_name: Font family name (default "Arial") bold: Whether the font is bold italic: Whether the font is italic rotation: Text rotation in degrees (0, 90, 180, 270) underline: Whether the font is underlined strikeout: Whether the font has strikeout Returns: Dictionary with font_id |
| obj_selectA | Select objects matching a filter on the active document. Sets the selection state on matching schematic or PCB objects for
visual highlighting. Use Args: object_type: Altium object type (schematic or PCB) filter: Pipe-separated property=value conditions (AND logic) Returns:
|
| obj_deselect_allA | Clear all object selection on the active document. Returns: Dictionary confirming deselection |
| obj_zoomB | Control the viewport zoom level. Args: action: "fit" (zoom to show all), "selection" (zoom to selected objects) Returns: Dictionary confirming the zoom action |
| sch_mirror_componentA | Mirror a placed schematic component horizontally. USE THIS RATHER THAN WRITING Altium's own mirror does both halves at once, setting the flag AND reflecting the primitives, and so does this. That matters twice over: a part mirrored here is identical on disk to one mirrored by hand, and the flag is instance data, so the result survives Update From Libraries. Reflecting the primitives alone would be undone the next time anyone re-instantiates the symbol. Args: designator: component to mirror, e.g. "U1" mirrored: True or False for an absolute state; omit to toggle. Asking for the state it already has is a no-op, not a second reflection. doc_path: sheet to act on. Defaults to the focused schematic. Every primitive is reflected about the component's X: pins (left and right swap), lines and rectangles by both ends, polygons, polylines and Beziers by every vertex, and arcs by their centre with their sweep mirrored. A primitive kind it cannot reflect is left where it was and counted in primitives_skipped. Returns: Dictionary with designator, mirrored (the resulting state), primitives_moved, primitives_skipped, and changed. |
| obj_batch_modifyA | Apply many filter+set operations in ONE IPC round-trip. PREFER THIS over looping Use it for: moving multiple pins to specific positions, re-laying component placement, per-sheet title changes, bulk designator rewrites, any workflow where each object gets its own value. A DESIGNATOR BATCH IS WORTH A NETLIST CHECK AFTERWARDS. There is
no transaction rollback here: if an op fails part way the earlier
ones stay applied, and duplicate designators are not an error
Altium reports. Two parts left sharing Args: operations: List of operation dicts, each with: - scope: "active_doc" (default), "project", "doc:C:\path\to\file.SchDoc", or "lib_component:NAME" -- a named symbol in the active SchLib. Mixing lib_component scopes across ops edits many library symbols in ONE call, no per-symbol lib_set_current_component round-trip. - object_type: Altium object type (e.g., "ePin", "eParameter", "eSchComponent", "eNetLabel"), or a PCB type such as "eTrackObject", which edits the active board and takes only scope "active_doc" - filter: Pipe-separated filter conditions (e.g., "Designator.Text=U1", "Name=VDD") - set: Pipe-separated property=value assignments (e.g., "Location.X=300|Location.Y=-100|Orientation=2") Returns:
Dictionary with operations_processed, operations_skipped,
total_matched, and a per-operation Example, edit pins across THREE different library symbols in ONE call: obj_batch_modify(operations=[ {"scope": "lib_component:R_0402", "object_type": "ePin", "filter": "Designator=1", "set": "Name=A"}, {"scope": "lib_component:C_0402", "object_type": "ePin", "filter": "Designator=1", "set": "Name=+"}, {"scope": "lib_component:LED_0603", "object_type": "ePin", "filter": "Designator=1", "set": "Name=K"}, ]) Example, reposition 10 pins on a library symbol in ONE call
(vs. 10 separate Example, update 4 parameters across every project sheet in ONE call: obj_batch_modify(operations=[ {"scope": "project", "object_type": "eParameter", "filter": "Name=Engineer", "set": "Text=John Smith"}, {"scope": "project", "object_type": "eParameter", "filter": "Name=Revision", "set": "Text=2.0"}, {"scope": "project", "object_type": "eParameter", "filter": "Name=Organization", "set": "Text=Acme Corp"}, {"scope": "project", "object_type": "eParameter", "filter": "Name=CompanyName", "set": "Text=Acme Corp"}, ]) Example, different titles on specific sheets in ONE call: obj_batch_modify(operations=[ {"scope": "doc:C:\path\TopLevel.SchDoc", "object_type": "eParameter", "filter": "Name=Title", "set": "Text=Top Level"}, {"scope": "doc:C:\path\PSU.SchDoc", "object_type": "eParameter", "filter": "Name=Title", "set": "Text=Power Supply"}, ]) |
| obj_run_processB | Run an Altium process command via the generic primitive layer. Wraps any Altium RunProcess call with structured pipe-separated parameters. Args: process_name: The Altium process identifier (e.g., "Sch:Compile", "WorkspaceManager:OpenObject", "PCB:Zoom") parameters: Optional pipe-separated key=value parameter pairs, e.g.: "ObjectKind=Document|FileName=C:\path\to\file.SchDoc" Returns: Dictionary with execution result |
| proj_run_ercA | Run Electrical Rules Check on the focused project. Compiles the project first (required), then runs ERC.
Call Returns: Dictionary confirming ERC execution |
| sch_set_components_parametersA | Bulk-update parameters on PLACED schematic components. Single IPC call wraps N component updates inside one
PreProcess/PostProcess undo group. Avoids the 10-100x slowdown
of looping the singular variant. The canonical follow-up tool
after audits that flag parameter-level bugs --
Each stamp targets one component by designator and sets one or more parameters. Special keys allowed:
Args:
stamps: List of dicts. Each dict must include Returns:
Dict with |
| proj_get_erc_violationsA | Return the ERC violation list produced by the last
Two-step pattern by design: Each violation names the OBJECTS it is about, not just a
category. That detail is the difference between a report and something actionable. A category plus a sheet name cannot be acted on: the only safe response to "floating input pin, somewhere on this sheet" is to do nothing, because a NoERC marker placed by guesswork silently suppresses a real disconnection and is worse than the warning it clears.
Returns:
|
| obj_highlight_netA | Highlight a net by name in the focused schematic or PCB document. PCB path sets IPCB_Net.IsHighlighted on the matched net (the documented property). Schematic path walks net labels / power ports / ports / sheet entries on the active sheet and marks those whose name matches as Selection=True, the closest thing Altium exposes to a "highlight" on schematic without interactive commands. If a schematic is the focused document, this paints the
schematic even when a PcbDoc is also open. Pass
Args:
net_name: Exact net name to highlight (e.g., "VCC", "GND",
"NET_D0"). Returns NOT_FOUND if the net doesn't exist
on the PCB, or Returns:
Dict with success, net, context ("pcb" or "schematic"), and
|
| obj_crossref_netA | Compare the schematic vs PCB membership of a named net. Returns the full pin list the SCHEMATIC assigns to this net alongside the pad list the PCB assigns to the same net, plus the diff in each direction. USE THIS when:
Args: net_name: Exact net name as it appears in the schematic (case-sensitive). Returns:
Dict with:
- net_name
- sch_pin_count, pcb_pin_count
- matched (count of pins present on both sides)
- sch_only_count, pcb_only_count
- in_sync (True only when both sides list the same pins
AND the net exists on at least one side)
- sch_pins[], pcb_pins[], each entry is
"Designator.PinNumber"
- sch_only[], pcb_only[], the diff lists. If
|
| obj_clear_highlightsB | Clear all net highlights in the active schematic or PCB document. Returns: Dictionary confirming highlights were cleared |
| proj_add_sheetA | Create a new schematic sheet and add it to the focused project. The sheet is created in the same directory as the project file. Args: name: Name for the new sheet (without .SchDoc extension). Default "NewSheet". Returns: Dictionary with the path of the newly created sheet |
| proj_delete_sheetA | Remove a schematic sheet from the focused project. Safety check: refuses to remove the last remaining schematic sheet. The file is closed and removed from the project but not deleted from disk. Args: file_path: Full path to the .SchDoc file to remove Returns: Dictionary confirming removal |
| obj_switch_viewA | Toggle between 2D and 3D view for PCB documents. Args: mode: Target view mode, "3d" or "2d" (default "3d") Returns: Dictionary confirming the view switch |
| obj_refresh_documentA | Force a redraw/refresh of the current document. For schematics, calls GraphicallyInvalidate. For PCB, sends a PCB:Zoom Redraw command. Returns: Dictionary confirming the refresh |
| proj_get_unconnected_pinsA | Find unconnected/floating pins in the focused project. Compiles the project first (required for connectivity data), then iterates all components via the DM API to check pin connection status. Returns: Dictionary with "count" and "unconnected_pins" array, each entry having designator, pin_number, pin_name, and sheet path |
| sch_stub_pinsA | Draw a short wire stub + net label on every unconnected schematic pin. Finds floating pins (via the same connectivity check as
Args: stub_length_mils: Length of each stub wire in mils (default 100) only_designators: If given, only stub pins on these components Returns: Dictionary with "stubbed" and "failed" counts, plus the pin list that was acted on |
| sch_place_rectangleA | Place a rectangle shape on the active schematic (decorative only). Args: x1, y1, x2, y2: Opposite corners in mils solid: Fill the rectangle (default False = outline only) line_width: 1 (small), 2 (medium), 3 (large) Returns: Dictionary confirming rectangle placement |
| sch_place_lineA | Place a decorative line on the active schematic. This is a graphic line, not a signal wire. Use Args: x1, y1, x2, y2: Endpoints in mils line_width: 1 (small), 2 (medium), 3 (large) Returns: Dictionary confirming line placement |
| sch_place_noteA | Place a text-box note on the active schematic. Useful for design commentary, TODO markers, revision notes. The box sizes itself to (x1,y1)-(x2,y2) and contains the given text. Args: x1, y1, x2, y2: Note box corners in mils text: Note content Returns: Dictionary confirming note placement |
| sch_place_sheet_symbolA | Place a sheet symbol linking to a child schematic document. Used for hierarchical designs, the parent sheet has one sheet symbol per child .SchDoc in the project. The sheet_file_name must exactly match a .SchDoc that's a project member. Without that match the sheet symbol is dangling. After placing, use Args: x1, y1, x2, y2: Sheet symbol box corners in mils sheet_file_name: Child SchDoc filename (e.g. "PSU.SchDoc") sheet_name: Display label (default: file name without extension) Returns: Dictionary confirming sheet symbol placement |
| sch_place_sheet_entryA | Place a sheet entry port on an existing sheet symbol. Sheet entries are the ports on a sheet symbol that map to hierarchical ports inside the child sheet. Name must match a port defined in the child .SchDoc for electrical continuity. Args: sheet_name: SheetName of the target sheet symbol entry_name: Port name (must match a port in the child sheet) io_type: "input" | "output" | "bidirectional" | "unspecified" side: "left" | "right" | "top" | "bottom" distance_from_top: Position along the chosen side in mils Returns: Dictionary confirming sheet entry placement |
| sch_place_bus_entryA | Place a bus entry (45 degree stub) connecting a wire to a bus. Bus entries are the angled stubs that tap a single-signal wire off a bus line. Start point should sit on the bus; end point should sit on the wire (both usually at 45 degrees offset). Args: x1, y1: Start coordinates in mils (typically on the bus) x2, y2: End coordinates in mils (typically on the wire) Returns: Dictionary confirming bus entry placement |
| sch_set_sheet_sizeA | Set the sheet size / template style of the active schematic. Changes SheetStyle on the current SchDoc. Use a named style
(A-E, A0-A4, Letter, Legal, Tabloid) or "Custom" with explicit
width and height in mils. Give Args: style: Sheet size name, e.g. "A", "A3", "A4", "Letter", "Custom" custom_width: Custom sheet width in mils (only if style="Custom") custom_height: Custom sheet height in mils (only if style="Custom") orientation: "landscape" or "portrait"; empty leaves it as is Returns: Dictionary confirming the style change |
| sch_place_busA | Place a bus segment between two XY coordinates on the active schematic. Buses carry multi-signal groups like DATA[0..7]. Place a bus line and then attach net labels with the bus naming syntax to mark the signal group. Typical workflow: bus line, bus entries at each pin, then connect each bus entry to a wire. Args: x1: Start X coordinate in mils y1: Start Y coordinate in mils x2: End X coordinate in mils y2: End Y coordinate in mils Returns: Dictionary confirming bus placement with coordinates |
| sch_place_net_labelB | Place a net label at coordinates on the active schematic. Args: text: Net name for the label (e.g., "VCC", "GND", "SDA") x: X coordinate in mils y: Y coordinate in mils orientation: Label rotation (0=0deg, 1=90deg, 2=180deg, 3=270deg) Returns: Dictionary confirming placement |
| sch_place_portA | Place a port on the active schematic for inter-sheet connectivity. Args: name: Port name (maps to net name) x: X coordinate in mils y: Y coordinate in mils style: Arrow style, "none", "left", "right", "left_right" io_type: I/O direction, "unspecified", "output", "input", "bidirectional" Returns: Dictionary confirming placement |
| sch_place_power_portA | Place a power port symbol (VCC, GND, etc.) on the active schematic. Args: text: Net name for the power port (e.g., "VCC", "GND", "+3V3") x: X coordinate in mils y: Y coordinate in mils style: Symbol style: "circle", circle symbol (default, typical for VCC) "arrow", arrow symbol "bar", bar/line symbol "wave", wave symbol "gnd_power", power ground symbol "gnd_signal", signal ground symbol "gnd_earth", earth ground symbol orientation: which way the glyph points from the connection point: 0=right, 1=up, 2=left, 3=down. Leave at -1 to let the bridge decide by style, which sends the ground glyphs down and everything else up. Returns: Dictionary confirming placement |
| sch_get_sheet_parametersA | Get title block parameters (title, revision, date, etc.) from a schematic sheet. Reads all parameters from the sheet without modifying anything. Args: file_path: Full path to a specific .SchDoc file. If empty, reads from the active document. Returns: Dictionary with "count" and "parameters" array, each having "name" and "value" |
| obj_copyA | Copy matching schematic objects to the clipboard. Selects objects matching the filter, copies them to the system clipboard, then clears selection. Args:
object_type: Altium schematic object type (see Returns: Dictionary with count of copied objects |
| obj_countA | Quick count of objects by type, faster than Args:
object_type: Altium object type constant (see Returns: Dictionary with "count" (and "sheets_processed" for project scope) |
| sch_place_no_ercA | Place a No-ERC marker at coordinates to suppress specific ERC violations. Use this after running ERC to suppress known-good violations at specific pin or wire locations. Args: x: X coordinate in mils y: Y coordinate in mils Returns: Dictionary confirming placement with coordinates |
| sch_place_junctionA | Place a MANUAL junction at coordinates on the active schematic. A T NEEDS NONE. Altium draws an automatic junction wherever a wire ends on another wire or three wire ends meet, blue, exactly as interactive wiring leaves it, and it does so for wires this server places too. The object this tool creates is a manual junction: drawn dark red with a lock marker, and placed on a T it just sits on top of the blue one. Use it only where two wires CROSS and must connect. A plain crossing is not a connection in Altium, and a manual junction is what makes it one. Args: x: X coordinate in mils y: Y coordinate in mils Returns: Dictionary confirming placement with coordinates |
| obj_get_document_infoA | Get comprehensive info about the active document. For schematics: file path, kind, sheet size, title block visibility, snap grid, visible grid, unit system, and custom dimensions. For PCB: file path, kind, origin, snap grid. Returns: Dictionary with document properties |
| obj_set_gridA | Set the snap grid and/or visible grid size for the active schematic. Args: snap_grid: Snap grid size in mils (0 = don't change) visible_grid: Visible grid size in mils (0 = don't change) Returns: Dictionary with the resulting grid sizes |
| sch_set_unitsA | Set the unit system for the active schematic. Calls ISch_Document.SetState_Unit with a TUnit enum value. The
current unit is readable via Args: unit: one of "mil" , imperial, mils (0.001 in) "inch" , imperial, inches "dxp" , DXP default "auto_imperial" , auto-scaled imperial display "mm" , metric, millimetres "cm" , metric, centimetres "m" , metric, metres "auto_metric" , auto-scaled metric display Returns: Dictionary confirming the change, with the resulting unit_system ("imperial" or "metric"). |
| sch_add_directiveA | Place a parameter-set directive at (x, y) on the active schematic. A parameter-set directive attaches a single
Args: x, y: Location in mils, place ON the target wire/net. param_name: Parameter name (e.g. "NetClass", "DifferentialPair") param_value: Parameter value Returns: Dictionary confirming placement. |
| sch_get_directivesA | Enumerate parameter-set directives on the active schematic sheet. Returns every ISch_ParameterSet on the sheet along with its location and the list of parameters it carries. Use this to audit which nets have explicit NetClass / DifferentialPair / custom-rule assignments before a compile, or to verify a bulk placement worked. Returns:
Dictionary with |
| sch_place_imageA | Place an image/logo on the active schematic. Args: image_path: Full path to the image file (BMP, JPG, PNG, etc.) x: X coordinate in mils (bottom-left corner) y: Y coordinate in mils (bottom-left corner) width: Image width in mils (default 500) height: Image height in mils (default 500) Returns: Dictionary confirming placement with path and dimensions |
| proj_replace_componentA | Replace a component with a different library part. Keeps existing connections and designator, swaps the symbol and library reference. The component must exist on the active schematic sheet. Args: designator: Component designator to replace (e.g., "U1", "R3") new_lib_ref: New library reference / component name new_library: New source library name (optional, keeps current if empty) Returns: Dictionary confirming the replacement |
| sch_clear_source_libraryA | Unpin placed schematic components from a stale source library. Schematic mirror of
Per matching component this clears SourceLibraryName (when set) and syncs DesignItemId to LibReference (when they differ), so Altium re-matches from whatever is currently in Available Libraries. Both actions are independently switchable. DesignItemId is a component property, NOT a parameter: writing
it through the parameter-stamping API only creates a stray user
parameter of that name. Use this tool (bulk) or Args:
sheet_path: absolute .SchDoc path; empty = the focused
sheet. For a whole project, call once per sheet (see
proj_list_documents).
designators: restrict to these designators (whole-string,
case-sensitive); None/empty = every component on the
sheet.
clear_source_library: clear Returns: {"total": inspected, "cleared_source_library": n, "synced_design_item_id": n}. |
| sch_get_constraint_groupsA | Enumerate IDocument.DM_ConstraintGroups on the active schematic. Constraint groups are FPGA-style pin/timing constraints attached to a document. Each group has a target kind and id, plus a list of IConstraint entries with a kind/data payload. Useful for auditing FPGA pin assignments and timing constraints that don't show up in the regular PCB design-rule list. Returns: Dict with groups (list of {target_kind, target_id, constraint_count, constraints[{kind, data}, ...]}) and count. |
| sch_place_harness_connectorA | Place a harness connector on the active schematic sheet. Harness connectors group a set of wires/buses into a named signal bundle, letting cross-sheet connections be drawn as a single line instead of a bus. Args: x, y: Bottom-left corner in mils. width, height: Connector rectangle size in mils. harness_type: Named harness type (optional). Returns: Dict with success, x, y, width, height, harness_type. |
| sch_place_cross_sheet_connectorA | Place a cross-sheet connector (off-sheet port) on the active sheet. Cross-sheet connectors are the hierarchical equivalent of a net label, they connect a signal to the same net name on another sheet. Args: x, y: Connector location in mils. net: Net name the connector binds to. side: "left" or "right" orientation (optional). Returns: Dict with success, x, y, net. |
| sch_place_text_frameA | Place a multi-line text frame (note block) on the active sheet. A text frame is a bordered rectangle that word-wraps a block of
text. Use Args: x1, y1, x2, y2: The two rectangle corners in mils. text: Frame contents (use \n for line breaks). align: Horizontal alignment "left", "center", or "right". Returns: Dict confirming placement and the frame corners. |
| sch_generate_tocA | Place a table-of-contents note listing every schematic sheet. Reads the project's document list, keeps the .SchDoc sheets in project order, and drops a numbered text frame on the active sheet. Run it on a dedicated cover/index sheet. Re-running does not remove a prior frame, delete the old one first if you regenerate. Args: x1, y1, x2, y2: Frame corners in mils (default a tall left box). title: Heading line above the list. project_path: Optional project; uses active if omitted. Returns: Dict with sheet_count and the placement result, or an error if no schematic sheets were found. |
| sch_set_net_tieA | Mark a placed schematic component as a net tie. A net tie shorts the nets that land on its pins for routing while keeping them as separate logical nets (so ERC/DRC treat the join as intentional). Sets the component's ComponentKind. Use on a dedicated net-tie footprint/symbol you have already placed and wired. Args: designator: Component to convert (e.g. "NT1"). mode: "nobom" (default, hidden from BOM, kept through sync) or "bom" (appears in the BOM). Returns: {"designator", "component_kind"} or NOT_FOUND. |
| sch_increment_designatorsA | Offset the trailing number of schematic designators by a delta. Adds Args: delta: Non-zero integer added to each designator's number. prefix: If set (e.g. "R"), only designators with this letter prefix are changed. Returns: Dict with success, modified (count), delta. |
| sch_toggle_pin_visibilityA | Show or hide pin name / designator labels on schematic symbols. Targets a single component (by Args: designator: Component to target, or "" for all components. show_name: True/False to set pin-name visibility (optional). show_designator: True/False to set pin-designator visibility. Returns: Dict with success and pins_modified (count). |
| sch_set_component_part_idA | Switch the active sub-part on a multi-part schematic component. Multi-gate parts like quad op-amps expose one sub-part per gate (U1A, U1B, U1C, U1D). CurrentPartID selects which one this symbol instance represents. IDs are 1-based. A DESIGNATOR IS NOT UNIQUE HERE. Every sub-part of a multi-part device carries the same one, so "U13" can name three symbols on the sheet. When it names more than one and no location is given this REFUSES, and returns the candidates with their locations, current part ids and unique ids. It used to write whichever the iterator reached first and report success naming only the designator, so the caller could not tell which symbol changed. Location is the discriminator because the alternatives do not work: two symbols can sit on the same part, and sub-parts of one physical device are supposed to SHARE a unique id. Args: designator: Component reference (e.g., "U1"). part_id: Sub-part index, 1-based (1=A, 2=B, ...). A value above PartCount is accepted by Altium and does not take, so the result is read back and a mismatch is reported. location_x: Symbol X in mils, to choose one of several. location_y: Symbol Y in mils, to choose one of several. Returns:
Dict with success, designator, part_id, the location written
and how many symbols carried the designator. On ambiguity,
an AMBIGUOUS_DESIGNATOR error carrying |
| sch_set_component_unique_idA | Set UniqueId on every placed symbol with this designator. ECO treats sub-parts of a multi-gate symbol (quad comparator, dual op-amp) as one physical footprint only when they share UniqueId. Four copies of part 1 with four UniqueIds become four packages. EVERY MATCHING SYMBOL IS STAMPED, not the first. Sharing the id is the whole point of the property, so writing one of three and reporting success left the other two pointing at packages of their own, which is the exact condition this repairs. Altium mints UniqueIds itself and may keep its own. Each write is read back and COMPARED; if any symbol kept its old id the call fails and names which ones, because a partial stamp still leaves the device split. Args: designator: Component reference as drawn (e.g. "U_COMP2B"). unique_id: Target UniqueId, usually copied from the A unit. Returns: Dict with success, designator, unique_id, symbols_written, symbols_found, and per-symbol locations with the id each reads back. |
| sch_replicate_componentA | Copy a placed schematic part and share the master's UniqueId. ECO groups multi-part packages (quad comparators, dual op-amps) only when every unit has the same UniqueId. Writing UniqueId after the copy is already on the sheet remints a new id if that value is already present. This path stamps UniqueId on the replica before AddSchObject, which is the share that sticks. Finds the first instance whose designator matches, Replicates it, optionally switches CurrentPartID, optionally moves it, and keeps the master's UniqueId. Args: designator: Source instance to copy (e.g. "U8"). part_id: 1-based CurrentPartID for the copy. 0 = keep source. x, y: Placement in mils. Omit both to leave the replica where Replicate dropped it. new_designator: Designator for the copy. Empty keeps the source designator (required for multi-part packing). Returns:
Dict with success, source/copy UniqueIds, part_id, and
|
| sch_place_probeA | Place a probe/measurement marker on the active schematic. Probes mark nodes for SPICE/simulation output. Attach one to a wire to declare "capture voltage / current at this point" in simulation runs. Args: x, y: Probe location in mils. net_name: Optional explicit net label text. probe_method: "probed_nets_only" (default) or "all_nets". Returns: Dict with success, x, y, net_name. |
| sch_add_datafile_linkA | Attach a datafile link to a component's current implementation. Datafile links are how parametric data (IBIS model files, sim models, external CSVs) is bound to a schematic part. Args: designator: Component reference (e.g., "U1"). file_path: Full path to the file being linked. kind: Optional implementation-specific type (e.g., "SimModel", "IBIS"). Returns: Dict with success, designator, file_path. |
| obj_batch_createA | Create many schematic objects in ONE IPC round-trip. PREFER THIS over looping Args:
operations: List of create dicts, each with:
- scope: "active_doc" (default), only active_doc is
currently honored for creates.
- object_type: Altium type name (e.g. "eNetLabel",
"eJunction", "eNoERC").
- properties: pipe-separated Example, drop 3 net labels in one call: obj_batch_create(operations=[ {"object_type": "eNetLabel", "properties": "Text=VCC|Location.X=100|Location.Y=200"}, {"object_type": "eNetLabel", "properties": "Text=GND|Location.X=100|Location.Y=400"}, {"object_type": "eNetLabel", "properties": "Text=SCK|Location.X=300|Location.Y=200"}, ]) Returns: Dict with created, failed, total counts and indexed failures. Known unsupported properties (IsHidden on anything but pins, parameters, designators and sheet names; Text on a type without it, such as eParameterSet or eWire) reject that item before registration. Its failure includes reason UNSUPPORTED_PROPERTY, property and object_type. Other valid items still run. |
| obj_batch_deleteA | Delete matching objects across many scope/type/filter operations. PREFER THIS over looping Args:
operations: List of delete dicts, each with:
- scope: "active_doc" (default), "project", or
"doc:<absolute_path>".
- object_type: Altium type name (e.g. "eJunction",
"eNoERC", "eWire", or a PCB type such as
"eTrackObject", which deletes from the active board
and takes only scope "active_doc").
- filter: pipe-separated Example, purge all no-ERCs on a specific sheet and every junction on the project. Both filters are empty, so the confirmation is required: obj_batch_delete(confirm_delete_all=True, operations=[ {"scope": "doc:C:\proj\Power.SchDoc", "object_type": "eNoERC", "filter": ""}, {"scope": "project", "object_type": "eJunction", "filter": ""}, ]) Returns:
Dict with operations_processed, total, total_deleted and
|
| sch_place_wiresA | Place MANY wire segments on the active schematic in ONE call. NOT THE WAY TO WIRE A DESIGN. Routing a netlist segment by segment means choosing every corner yourself, and the result reads like nothing a person would draw. design_execute_plan routes the whole sheet from a DesignPlan through the layout engine, deciding wire-versus-label per net and keeping wires off other nets' pins. Use THIS tool for a few segments on a sheet that already exists. PREFER THIS over placing wires one segment at a time (there is no singular variant). Wiring up a netlist is inherently N pairs of endpoints; the bulk version is 10-100x faster in wall time because the whole batch shares one PreProcess/PostProcess and one redraw. Args: wires: List of wire dicts, each with x1, y1, x2, y2 in mils. Example, a 3-segment L-shaped bus routing: place_wires(wires=[ {"x1": 100, "y1": 200, "x2": 300, "y2": 200}, {"x1": 300, "y1": 200, "x2": 300, "y2": 400}, {"x1": 300, "y1": 400, "x2": 600, "y2": 400}, ]) Returns: Dict with placed, failed, total counts. |
| sch_place_componentsA | Place MANY schematic components from libraries in ONE call. NOT THE WAY TO DRAW A SCHEMATIC, AND IT IS ENFORCED. Placing four
or more components onto a sheet that has two or fewer is refused:
that is a schematic being drawn by hand, and positions chosen that
way read like nothing a person would draw however correct the
netlist is. Build a DesignPlan and call design_execute_plan
instead, which places AND routes the whole sheet through a layout
engine measured against hand-drawn boards; design_layout_schematic
and design_preview_plan show you the result first without touching
the EDA. Use THIS tool to add parts to a sheet that already exists,
or when the positions came from that engine. To place coordinates
yourself anyway, pass This is the only path for library placement (there is no singular variant). Laying out a 50-part BOM is inherently a bulk operation; done one-by-one it would cost 50 LLM turns. TARGET DOCUMENT: placement lands on the ACTIVE schematic. Right
after Args: allow_manual_layout: Set True to bypass the refusal described above and place your own coordinates onto an empty sheet. The default exists because this is almost never what the caller actually wants; say why in the surrounding turn. document_path: Absolute path of the .SchDoc to place onto. When given, it is focused before placement so parts can't land on the wrong sheet. When omitted, the current active document is used. placements: List of placement dicts, each with: - library_path (str, optional, empty uses an already-open library) - lib_reference (str, required), component name - x, y (int, mils), placement location - designator (str, optional), override designator - rotation (int, optional), 0 / 90 / 180 / 270 - footprint (str, optional), override current footprint Example, place a 5-part BOM row: sch_place_components(placements=[ {"library_path": "C:\Lib\ST.SchLib", "lib_reference": "STM32F411RE", "x": 1000, "y": 2000, "designator": "U1"}, {"library_path": "C:\Lib\Res.SchLib", "lib_reference": "Res1", "x": 1500, "y": 2000, "designator": "R1"}, ... # 3 more ]) Returns: Dict with placed, failed, total counts. |
| sch_place_vault_componentsA | Place MANY managed (Workspace) components in ONE call.
A part number is not looked up here, so bring the Design Item ID.
Args:
placements: List of dicts, each with "design_item_id"
(required), Returns:
|
| sim_attach_primitivesA | Attach SPICE primitives to MANY components in ONE call. PREFER THIS after running Args: attachments: List of attach dicts, each with: - designator (str, required) - primitive (str, required), R/L/C/V/I/D/Q/M/X - value (str, optional), "10k", "100n", "DC 5", "SIN(0 1 1k)", etc. - spice_model (str, optional), model name for semi/sub-circuit parts - sim_kind (str, optional), "General" / "Subcircuit" / "Model" Example, attach the 4 passives from a readiness audit: sch_attach_spice_primitives(attachments=[ {"designator": "R1", "primitive": "R", "value": "10k"}, {"designator": "R2", "primitive": "R", "value": "10k"}, {"designator": "C1", "primitive": "C", "value": "100n"}, {"designator": "C2", "primitive": "C", "value": "1u"}, ]) Returns: Dict with attached, failed, total counts. |
| pcb_get_netsB | Get all unique net names from the active PCB board. Returns: Dictionary with "nets" array of net name strings and "count" |
| pcb_focus_boardA | Make a specific PCB the focused/current board. When several PcbDocs are open, the other PCB tools
( Args: board_path: Absolute path to the .PcbDoc to focus. Returns:
Dict with |
| pcb_delete_netA | Delete nets from the active PCB. By default removes only EMPTY nets (no connected pads / tracks /
vias): the cleanup for stray nets left behind after deleting
components, e.g. nets created by Args: nets: Specific net names to delete. Omit (or pass an empty list) to sweep ALL empty nets on the board. force: Also delete nets that still have connected primitives (orphans them). Default False. A net name containing a COMMA is refused rather than sent. The
list rides one comma-separated field and the handler splits it
with Returns:
Dict with |
| pcb_get_net_classesA | Get all net classes on the active PCB, with the nets in each. Altium's script host does not expose a class's member list, so
each class is asked about every net in turn. That is one call per
class and net, so on a big board Args: members: Read each class's nets (default). False returns the class names only. Returns: Dictionary with "net_classes" (each with name, super_class and, when members are read, "nets", "member_count" and "probe_errors"), "count" and "members_read". A class with probe_errors above 0 may have more nets than listed. |
| pcb_create_net_classA | Create a net class (or add nets to an existing one) on the active PCB. Args: name: Name for the net class (e.g., "PowerNets", "HighSpeed") nets: Comma-separated list of net names to add (e.g., "VCC,GND,3V3") Returns: Dictionary with class_name, class_created (bool), nets_added count |
| pcb_create_nets_from_listA | Create net objects on the active PCB for names not already there. First leg of the netlist-driven SCH->PCB bridge (Altium's ECO is
not scriptable): place footprints with Args: nets: Net names to ensure exist (e.g. from the compiled netlist). Duplicates and empty strings are ignored. Returns:
Dict with |
| pcb_bind_pad_netsA | Assign component pads to existing board nets, batch in ONE call. Second leg of the netlist-driven SCH->PCB bridge: after
Bindings are processed in order; keep rows for the same
designator adjacent (the handler caches the component lookup per
consecutive run -- Args:
bindings: List of dicts, each with Returns:
Dict with |
| pcb_build_from_projectA | Build the PCB's net set and pad connectivity from the netlist. The SCH->PCB bridge orchestrator (replaces the unscriptable ECO
netlist transfer): derives the distinct net list and every
(designator, pin, net) binding from the compiled netlist, creates
the missing nets ( It does NOT place footprints -- Args:
netlist_csv_path: Optional path to a tabular netlist CSV
written by Returns:
Dict with |
| pcb_get_design_rulesA | Get all design rules from the active PCB. Reports every rule kind, including ones this toolset cannot create, because it iterates rule objects rather than switching on a kind.
A CLEARANCE-FAMILY RULE ALSO CARRIES Returns: Dictionary with "rules" array (each with name, rule_kind, enabled, priority, scope_1, scope_2, comment, descriptor, and gap_mm for clearance, component, hole-to-hole and board outline clearance rules) and "count". |
| pcb_set_rules_enabledA | Bulk-toggle the DRC-enabled flag on design rules by name. Useful for focused review passes: disable a noisy class of rules
to surface the violations that matter (e.g. silence Silk-to-Silk
while you sweep Clearance), or re-enable a set before a release
sweep. Matches case-insensitively; supports trailing-* wildcards
so a rule family can be targeted without listing every name
( Note that this flips Args:
names: Rule names to toggle. With Returns:
Dict with:
- |
| pcb_get_clearance_violationsA | Read the violations ALREADY on the board, optionally filtered to one net. Does NOT run DRC. This is a pure board read: it walks the It used to trigger CAVEAT -- Filter is substring-matched against the violation's Description and Name, so it catches both "Net USB_DP and Net GND" clearance warnings and net-named via antennas. Each violation carries Args: net: Net name to filter by (substring match). Empty string returns ALL stored violations. offset: How many matching violations to skip, for paging. limit: How many to return, 200 by default. Returns:
Dict with |
| pcb_run_drcA | Run Design Rule Check (DRC) on the active PCB. MODAL --
BLOCKS THE BRIDGE. Opt in with DANGER: Altium has no non-interactive DRC trigger exposed to
DelphiScript. PREFER PATHOLOGICAL CASE: a full DRC on a placed-but-unrouted board
(many components, zero tracks, everything unrouted) checks
every pad pair against every rule and is enormously slow for
an answer that is already known -- "nothing is routed yet".
Check With
Per-violation shape:
Use Args: allow_modal: Must be True to actually run DRC, and it means "I accept that the bridge blocks on a modal dialog until a human clicks it". Default False refuses without touching Altium. Returns:
Dict with |
| pcb_get_componentsA | Get all components from the active PCB with position and properties. DATASHEET DISCIPLINE: The response carries a Returns:
Dictionary with "components" array (each with designator, x, y,
rotation, layer, footprint) and "count", plus
|
| pcb_move_componentsA | Move and/or rotate MANY PCB components in ONE IPC round-trip. PREFER THIS over moving one component per call. Each singular move is a full LLM turn (5-15 s); one call to this tool repositions every component in the list in a single Altium transaction. Typical uses: applying a full layout pass, running an auto-placement result, undoing and redoing a placement set, adjusting a row of components relative to each other. Args: moves: List of move dicts. Each dict supports: designator (required) , target component x (optional) , new X in mils y (optional) , new Y in mils rotation (optional) , new rotation in degrees Returns: Dictionary with per-designator results and a count. |
| pcb_import_placementA | Position components from a coordinate list (pick-and-place import). The inverse of Args: placements: list of dicts, each supporting: designator (required) x (optional) , X in mils y (optional) , Y in mils rotation (optional) , degrees side (optional) , "top" or "bottom" layer (optional) , "TopLayer" / "BottomLayer" (overrides side) Returns: {"applied": N, "failed": M}. |
| pcb_add_teardropsA | Add teardrops to pad/via-track junctions board-wide. Launches Altium's Teardrop command on all objects. The Teardrop dialog is modal and cannot be suppressed from script (same limitation as the ECO dialog): choose Add and confirm it in Altium. Returns once the command is dispatched. |
| pcb_remove_teardropsA | Remove teardrops board-wide. Opens the same modal Teardrop dialog as |
| pcb_autoplace_silkscreenA | Move designators that break silk clearance to a clear position. A visible designator that is closer than the silk clearance to
anything else on its overlay layer (component outlines, texts,
fills), closer than the mask clearance to a pad's mask opening on
its side, or off the board, is tried at a ring of auto-position
anchors and left on the first that clears. A designator that is
already clear is not touched, and one no anchor clears goes back
where it was and is listed in Args:
silk_clearance_mils: Silk to silk clearance. Refused with NO_CLEARANCE, moving nothing, when a clearance is neither given nor readable from an enabled rule. Returns:
|
| pcb_tune_lengthA | Add approximate routed length to a net with a square serpentine. Lays a square meander on Open-loop and NOT DRC-checked: you choose where the meander goes and
verify clearance afterward ( Args: net: net name. add_length_mils: target length to add (mils). x_mils, y_mils: anchor point of the meander (mils). layer: routing layer (default TopLayer). amplitude_mils: meander height; bump count = add_length / (2*amplitude). width_mils: track width. Returns: {"length_before_mils", "length_after_mils", "added_mils", "bumps", "drc_checked": false}. |
| pcb_panelizeA | Build a production panel on the CURRENT (blank) PCB document. Open a new empty .PcbDoc and run this on it. Creates an embedded-board
array of Args: child_path: path to the source .PcbDoc to array. board_width_mils, board_height_mils: source board size (mils). rows, cols: array dimensions. col_gap_mils, row_gap_mils: spacing between adjacent boards. border_mils: rail width around the array (also half the tooling inset). tooling_holes, fiducials: whether to add them. Returns: {"panel_width_mils", "panel_height_mils", "rows", "cols", "tooling_holes", "fiducials"}. |
| pcb_delete_invalid_objectsA | Remove degenerate primitives from the active PCB. Deletes zero-length tracks and zero-area regions (board hygiene that accumulates from edits and imports). Returns the count removed. Returns: {"removed": N}. |
| pcb_audit_pad_center_connectedA | Find pads whose center has no copper entering it (acid-pad check). For every netted pad, checks that a track / arc / via on the same net reaches the pad centroid. A pad connected only at its edge (an "acid pad") can fail in fab. Read-only; reports offenders with designator, pad, net, and location. Returns: {"checked": N, "offenders": M, "items": [...]}. |
| pcb_auto_size_board_outlineA | Fit the board outline around the embedded-board array(s) plus a margin. Use after Args: margin_mils: border added on each side (default 100). Returns: {"width_mils", "height_mils"}. |
| pcb_normalize_viasA | Set free vias to their Routing Via rule's sizes, or to given ones. Without Args: size_mils, hole_mils: An explicit diameter and hole, together. net: Only vias on this net. from_size_mils, from_hole_mils: Only vias at this size now (within 0.05 mil), e.g. to fix one group. dry_run: Report what would change and change nothing. Returns:
|
| pcb_apply_via_templateA | Make free vias match a source via: its via template, hole and diameter. Point at a via that already uses the template you want (set one in Altium's Properties panel if none does), and every other free via, or those matching the filters, takes its template link, mode, hole and diameter. This is how to bring a board in line with a Routing Via rule in template mode. Altium Designer 22 or later. The template link is copied the way Altium's own FormatCopy script does it. Diameter and hole are read back; the link has no member to read back, so check one via's template in the Properties panel afterwards. Growing vias can create clearance violations: run DRC with the rules enabled. Args: source_x, source_y: A point on the source via, in mils. net: Only vias on this net. from_size_mils, from_hole_mils: Only vias at this size now. dry_run: Report what would change and change nothing. Returns:
|
| pcb_copy_designators_to_mechB | Copy each component designator onto a mechanical layer (assembly prep). Places a Args: layer: target mechanical layer (default Mechanical1). Returns: {"copied": N, "layer": "..."}. |
| pcb_trim_extend_trackA | Trim or extend one track endpoint along the track's own slope. Finds the track endpoint nearest (from_x, from_y), then slides it to the perpendicular projection of (to_x, to_y) onto that track's line. The track stays collinear (no bend introduced) and the opposite end stays put, so this cleanly lengthens a track up to a target or pulls it back. All coordinates in mils. Args: from_x, from_y: Picks which endpoint moves (nearest one wins). to_x, to_y: Target the moving end is projected toward. tolerance_mils: How close (from_x, from_y) must be to a real endpoint (default 5). Returns: {"moved_end", "old_x", "old_y", "new_x", "new_y", "layer"}. |
| pcb_cleanup_tracksA | Tidy stray track geometry: delete slivers and/or merge collinear runs. Modes:
Args: mode: "slivers", "merge", or "both" (default "slivers"). min_length_mils: Sliver threshold (default 1). Returns: {"slivers_deleted", "merged", "mode"}. |
| pcb_unrouteA | Take up the focused board's routing: its tracks, arcs and vias. Removes the free tracks and arcs on signal layers, and the free
vias, that carry a net. Never removes a footprint's own copper,
polygons or their hatching, dimensions, keepouts, or copper with
no net (an antenna, a logo, a heat spreader): those are drawn,
not routed. Locked routing stays unless Refuses unless the focused board is For other selections of board copper, Args: expect_file: full path of the board to un-route. nets: take up only these nets' routing. None takes every net's. A name that is not a net on the board refuses the whole call and nothing is removed. include_locked: take locked routing as well (default False). checkpoint: take a checkpoint first (default True). Returns:
|
| pcb_place_thieving_padsA | Fill bare copper area with a grid of isolated thieving pads. Drops a regular grid of small round pads on Args: layer: Copper layer to populate (default TopLayer). pad_size_mils: Pad diameter (default 20). pitch_mils: Grid spacing (default 50). clearance_mils: Keep-out from existing copper (default 15). margin_mils: Inset from board edge (default 100). Returns: {"placed", "scanned", "layer"}. |
| pcb_move_tracks_to_layerA | Move all tracks of a net to one layer, adding vias where needed. Relayers every track of Args: net_name: Net whose tracks move. target_layer: Destination signal layer (e.g. "BottomLayer"). via_size_mils: Via pad diameter for added vias (default 50). via_hole_mils: Via hole diameter (default 28). Returns: {"net", "target_layer", "moved", "vias_added"}. |
| pcb_bevel_polygon_cornersA | Chamfer the corners of a copper polygon pour. Replaces each sharp vertex with two points set back along its edges by bevel_mils (auto-clamped so neighbouring bevels never overlap), giving every corner a straight 45-style cut. Only straight-outline polygons are handled, a polygon containing arc segments is left untouched. The polygon is repoured after the edit. Args: index: Which polygon to bevel (0-based, in board iteration order). net_name: If set, count only polygons on this net when applying index. bevel_mils: Set-back distance per edge (default 25). Returns: {"beveled", "index", "orig_vertices", "new_vertices", "bevel_mils"}, or an error code (NOT_FOUND / BAD_POLYGON / HAS_ARC). |
| pcb_plan_placementA | Connectivity-driven auto-placement: shorten wirelength, keep components legal. Dry-run by default -- returns a proposed move list and quality metrics without touching the board. A pure-Python solver run on the current board. It reads the compiled netlist and every component's real footprint bounding box, then improves positions to minimize half-perimeter wirelength (HPWL) while keeping components inside the board outline and free of same-layer overlaps. Two solver cores are available via
With Workflow: call once with Seeding: by default the solver refines the board's CURRENT
positions (small, sensible nudges). Pass Args:
designators: If given, ONLY these components are moved; every
other placed component is held fixed but still attracts
its nets and blocks overlaps. If omitted, all components
are candidates (minus Returns:
Dict with:
- |
| pcb_copy_component_placementA | Clone placement from source components onto destination components. For each Real-world use: a board with N identical channels (filter / amp /
switching stages). Lay out channel 1 once, then call this tool
with a mapping like Mapping-driven rather than relying on sort-order matching of selections -- the agent-callable equivalent of a manual replicate. Args:
mapping: Returns:
Dict with:
- |
| pcb_replicate_layoutA | Replicate a routed channel's ROUTING onto a matching channel. Where Positioning: one rigid transform is derived from the FIRST mapping
pair (the anchor) -- the copied routing is rotated by
Which routing is copied (naming-agnostic): routing on nets
INTERNAL to the source group -- every component pad on the net
belongs to a mapped source component. Nets that escape the group
(a shared GND / power pour) are deliberately left alone. Pass an
explicit Preconditions: the destination components must already be placed
congruently with the source (e.g. run
Args:
mapping: Returns:
Dict with:
- |
| pcb_filter_variant_componentsA | Select a variant's components of one fitted-class on the board. Classifies every component under Args:
variant_name: The project variant to classify against.
select: Which class to select -- An unrecognised Returns:
{"variant", "select", "matched", "designators"}, or
|
| pcb_renumber_padsA | Renumber the current PcbLib footprint's pads in spatial order. The non-interactive form of the community RenumberPads tool: instead of clicking each pad in order, the footprint's pads are sorted by position and assigned sequential designators. Rows/columns are banded by a small tolerance so a grid numbers cleanly. Operates on the active PCB library's current footprint. Args:
order: Returns: {"renumbered", "order", "mapping": [{old, new}, ...]} or an error. |
| pcb_copy_tracks_radialA | Array the selected tracks/arcs/vias radially about a center point. Replicates the current selection Args:
center_x: Rotation-center X in mils.
center_y: Rotation-center Y in mils.
count: Total instances including the original (>= 2).
angle_step: Degrees between instances. Defaults to Returns: {"copied", "count", "angle_step"} or an error. |
| pcb_scaleA | Scale the selected free primitives by a ratio about an anchor. Each coordinate maps Args:
ratio: Scale factor (> 0). Returns: {"scaled", "skipped", "ratio", "anchor_x", "anchor_y"} or an error. |
| pcb_place_stitching_viasA | Place a grid of stitching vias on a named net within a rectangle. Standard RF / EMC tool: place GND stitch vias around high-speed traces so the return current has a low-inductance path between reference planes. Also used near connectors / clock generators / EMI-sensitive areas. Algorithm: walk a regular grid inside the rectangle; for each
gridpoint, spatial-iterate within The default is dry-run because mutating a board with N×M
new vias is risky. Confirm the Args: net: Target net (must already exist on the board). x1_mils, y1_mils, x2_mils, y2_mils: Inclusive rectangle where the grid is placed. PCB origin is bottom-left by Altium convention. spacing_mils: Grid spacing (default 50). For GND stitching near a high-speed bus, /4 of the wavelength of the highest harmonic is a common rule of thumb. via_size_mils: Via pad diameter (default 30). via_hole_mils: Via drill diameter (default 14). clearance_mils: Min gap to any non-same-net existing primitive (default 10). dry_run: When True (default), only count would-be placements without mutating the board. Returns:
Dict with |
| pcb_calc_impedanceA | Characteristic impedance of a PCB trace via IPC-2141 / Wadell closed-form approximations. Pure math, no Altium hit. Use this BEFORE routing a high-speed signal to pick the track width that matches your transceiver's target impedance (USB 90 Ω diff, HDMI 100 Ω diff, single-ended PCIe 50 Ω, MIPI 100 Ω diff, etc). For controlled-impedance fab spec sheets, the accuracy of these closed-form formulas is ± ~10% -- good enough for picking widths but fab houses will refine the actual stackup. For real controlled-impedance boards, send the stackup to your fab and use their Polar Si9000 / similar report values. Chaining with the layer stack: call Supported geometries:
Formula sources:
Args:
geometry: One of Returns:
Dict with:
- |
| pcb_calc_trace_width_for_impedanceA | Trace WIDTH to hit a target impedance (inverse of pcb_calc_impedance). The design-time complement: instead of "what impedance does this width
give?", it answers "I need 90 ohm USB / 100 ohm HDMI differential, or
50 ohm single-ended; how wide?". Inverts the same IPC-2141 / Wadell
closed forms, so it round-trips with the forward calc. Pure math, no
Altium. Same +/-10 % caveat -- a fab field solver refines the stackup;
read the real dielectric heights / er with Args:
target_ohms: Single-ended Z0 for Returns:
|
| pcb_calc_terminationA | Decide if a net needs termination and size the resistor(s). Two questions the impedance calc does not answer: is this net
electrically long for its edge rate, and -- if so -- what termination
value? A net stays a lumped wire while its one-way flight time is under
Args:
length_mils: Routed (or estimated) net length.
rise_time_ns: Signal edge rate (the driver's 10-90 % rise time).
z0_ohms: Line characteristic impedance (size it with
Returns:
|
| pcb_calc_length_matchA | Length-match tolerance and serpentine compensation for a bus / pair. Turns a timing budget into the length-match window the routing must hold,
and -- given the routed lengths -- the serpentine copper each net needs.
The complement of Altium's The skew budget is taken from Args:
lengths: Optional Returns:
|
| pcb_calc_thermal_viasA | Size a thermal-via field under a power pad (Fourier conduction). The thermal calcs answer "what junction-to-ambient resistance does the
part need" ( Args:
drill_mm: Finished via drill diameter.
board_thickness_mm: Conduction length -- top layer to the heat- The EasyEDA and KiCad builds
spell this Returns:
|
| pcb_calc_track_current_capacityA | IPC-2221 current-carrying capacity for a PCB track. Pure math, no Altium hit -- safe to call without an attached session. Returns the current the track can sustain at each of several temperature rises (1, 5, 10, 20, 30 °C above ambient), plus DC resistance if a length is supplied. Formula (IPC-2221, also IPC-2152's curve-fit predecessor):
Copper thickness conversion: 1 oz/ft² ≈ 1.378 mils. So
Resistance: Exposes the track-current math so the agent can apply it
across an entire power net after pulling track widths from
Args:
width_mils: Track width in mils.
copper_oz: Copper weight in oz/ft². Common values:
0.5 oz (HDI inner), 1.0 oz (standard), 2.0 oz (power
planes), 3.0 oz (heavy-current).
layer: Returns:
Dict with:
- |
| pcb_calc_trace_width_for_currentA | Minimum track WIDTH to carry a target current (inverse IPC-2221). The design-time complement of Solves Args:
current_amps: Target current the track must carry. The
EasyEDA and KiCad builds spell this Returns:
|
| pcb_add_testpoints_for_net_classA | For each net in a netclass that does NOT already have a
testpoint, place a new pad above the board outline with the
net assigned and the standard Typical workflow:
Coverage detection: a net is treated as "already covered" if
any pad or via on it carries ANY of the four testpoint flags
(so DFM tools, fab-side bed-of-nails vendors, and assembly-
side probe vendors all see the same coverage). Pass
Agent-friendly: no GUI, results returned for follow-up. Args:
net_class: Netclass name to scan.
type: Returns:
Dict with |
| pcb_apply_dnp_paste_exclusionA | Suppress stencil paste on Not-Fitted (DNP) components. The remediation half of With no Mechanism: each surface pad gets a manual PasteMaskExpansion of minus its larger dimension, which collapses the stencil aperture whatever the pad shape. Through-hole pads are left alone and counted separately, since they have no aperture to suppress. Reversible: RESTORE THE SAME LIST YOU APPLIED. The apply reply lists every component it touched in Apply is unaffected: with no Mismatch is visible either way. Args:
designators: Components to treat. Omit on an apply to use
the current variant's Not-Fitted list. Required on a
restore unless Returns:
Dict with |
| pcb_make_paste_gridA | Split a single pad's solder-paste opening into a grid of smaller fills. The classic use case is the central thermal pad on a QFN / DFN / QFP -- a full-area paste opening makes the IC "swim" sideways during reflow as the molten solder pool reduces friction. Splitting the opening into smaller squares totalling ~50-75% coverage gives the IC something to bond to while letting flux gases escape. Standard datasheet recommendations:
ALWAYS consult the IC manufacturer's recommended stencil pattern before defaulting to this script -- some packages specify a star, diagonal, or windowpane pattern; this tool only does a regular grid. Args:
designator: Component reference designator, e.g. Returns:
Dict with |
| pcb_get_differential_pairsA | Enumerate every Length mismatch between the two halves of a diff pair is one of the most common high-speed routing bugs. Transceiver specs:
Returns one row per pair with:
Uses the PCB API Returns:
Dict with |
| pcb_clear_source_footprint_libraryA | Clear Background: when a project is created from an Integrated
Library, every placed component remembers WHICH library it
came from. If the user later renames, moves, or consolidates
that library, ECO and "Update From Library" start failing
with "library not found" warnings because the component
still points at the stale path. Clearing
This is a standard step when consolidating multiple legacy libraries into a single curated library: drop the new lib into Available Libraries, call this tool, then run an ECO -- the components now bind to the new library. Generalized with an optional filter. Args:
designator_filter: Restrict to these designators
(e.g. Returns:
Dict with |
| pcb_get_fab_statsA | DFM (Design For Manufacturing) summary -- the numbers fab houses ask for on their quote forms. One IPC call returns:
Useful before sending gerbers to the fab: the agent can spot
sub-process-minimum values and warn the user. Aspect-ratio
check (depth / drill) is NOT included here because it
requires layer-stack walking; if you need it, fetch
Returns:
Dict with all keys above. All linear measurements use the
stated unit suffix ( |
| pcb_lock_net_routingA | Lock or unlock track / arc / via primitives on a list of nets. Standard workflow: before letting the autorouter touch the board,
lock the power / ground / clock / oscillator nets so a partial
re-route pass doesn't undo your careful hand-routing on them.
Set Locked primitives have The net-list-driven MCP equivalent of a cursor-driven lock. Args:
nets: Net names to lock / unlock (e.g. Returns:
Dict with:
- |
| pcb_set_text_visibilityA | Bulk-toggle component designator and / or comment visibility. For the common workflows:
Args:
designators: If True/False, set At least one of Returns:
Dict with:
- |
| pcb_set_text_styleA | Set the height and stroke width of component designators or comments. Silkscreen text size is usually a fabrication requirement (for
example 0.8 mm high with a 0.1 mm stroke: For free texts use Args:
height_mils: Text height in mils. At least one of Returns:
Dict with |
| pcb_check_placement_collisionA | Dry-run check whether moving a component to (x, y[, rotation]) would overlap any other placed component on the same side. DOES NOT actually move the component. Computes the predicted
axis-aligned bounding box at the proposed pose, then AABB-tests
against every other component's current bounding rect. Use this
BEFORE every Args: designator: Component to test (must exist on the board). x: Proposed X position in mils (component reference point). y: Proposed Y position in mils. rotation: Proposed rotation in degrees. When None the target's current rotation is used. Quarter-turn deltas (~+/-90 from current) swap the AABB dimensions; other angles use the current-orientation bbox as an approximation. margin_mils: Extra clearance to require around the target. Default 0 (touching bounding boxes count as collision). Returns: Dict with: - designator: target. - proposed: {x, y, rotation, bbox:{x1,y1,x2,y2}, margin_mils}. - clear: True if no collisions, False otherwise. - colliding_count: number of collisions. - colliding: list of {designator, bbox:{...}} per collider. Caveats: - AABB only; rotated non-square footprints will report an inflated bbox. - Same-side check is automatic; the target's bbox is compared only against components on the same layer (Top vs Bottom). - Does not detect courtyard violations or pad-to-pad clearances, only solid-box overlap. Use DRC for actual clearance rules. |
| pcb_get_trace_lengthsA | Get total routed track length per net on the active PCB. Sums all track segment lengths for each net. Useful for length matching analysis and checking differential pair balance. Args: net: Optional net name filter. If provided, only returns the length for that specific net. Empty = all nets. Returns: Dictionary with "trace_lengths" array (each with net name and length_mils) and "net_count" |
| pcb_get_layer_stackupB | Get the full PCB layer stackup information. Returns copper layers with thickness, dielectric type/height/constant, and board name. Returns: Dictionary with "layers" array (each with name, order, copper_thickness_mils, dielectric_type, dielectric_height_mils, dielectric_constant), "layer_count", and "board_name" |
| pcb_export_stackup_csvA | Write the layer stackup to a conventional fab CSV report. Fetches the structured stackup ( Args:
output_path: Destination .csv file. Defaults to
Returns: {"output_path", "rows", "layer_count", "total_thickness_mils"} or an error dict if the board / stackup could not be read. |
| pcb_add_layerA | Insert a copper layer into the PCB layer stack. Calls IPCB_LayerStack.InsertLayer with the requested TLayer enum. Valid names include MidLayer1..MidLayer30 (signal layers) and InternalPlane1..InternalPlane16 (power / ground planes). Top / Bottom are always present, they cannot be added. Args: layer: Layer name, e.g. "MidLayer1", "InternalPlane1" Returns: Dictionary confirming the layer was inserted. |
| pcb_remove_layerA | Remove a copper layer from the PCB layer stack. Calls IPCB_LayerStack.RemoveFromStack on the requested layer. Does nothing if the layer is not currently in the stack. Args: layer: Layer name, e.g. "MidLayer1", "InternalPlane2" Returns: Dictionary confirming the layer was removed. |
| pcb_modify_layerA | Tune properties on an existing copper layer. Every optional parameter is applied only if provided (non-empty string / non-zero number). Maps to: name IPCB_LayerObject.Name copper_thickness_mils IPCB_LayerObject.CopperThickness dielectric_type Dielectric.DielectricType (one of "none", "core", "prepreg", "surface") dielectric_height_mils Dielectric.DielectricHeight dielectric_constant Dielectric.DielectricConstant dielectric_material Dielectric.DielectricMaterial Args: layer: Target layer name, e.g. "MidLayer1" name: New layer name (optional) copper_thickness_mils: New copper thickness in mils (optional) dielectric_type: "none" | "core" | "prepreg" | "surface" (optional) dielectric_height_mils: New dielectric height in mils (optional) dielectric_constant: New Dk value (optional) dielectric_material: New dielectric material string (optional) Returns: Dictionary confirming the changes. |
| pcb_set_plane_netA | Tie an internal plane layer to a net. An Altium internal plane is a NEGATIVE layer: the copper is
everywhere except where the plane is cleared, and the net lives on
the LAYER, not on a poured object. Pouring a polygon on a plane
layer is a different thing and does not connect the plane, so this
is the tool for "make Internal Plane 1 the PGND plane" --
The net must already exist on the board (see The net is written to the board's InternalPlaneNetName for that
layer and READ BACK before reporting; if that does not take, the
layer object's own net is tried and read back too. When neither
reads back the net the call answers Args: layer: Internal plane layer, e.g. "InternalPlane1" or the name the stackup reports for it net: Existing net name to tie the plane to, e.g. "PGND" Returns: Dictionary with "success", "layer" (the RESOLVED layer), "layer_name", "net", "net_readback", "applied", "route" (which write took) and "note". |
| pcb_get_board_outlineA | Get the board outline vertices and bounding rectangle. Returns outline geometry as a list of vertices (line segments and arcs) plus the bounding rectangle dimensions. Returns: Dictionary with "point_count", "vertices" array (each with index, kind, x, y, and optionally cx, cy, angle1, angle2 for arcs), and "bounding_rect" (left, bottom, right, top in mils) |
| pcb_get_selected_objectsA | Get properties of currently selected objects on the active PCB. Args: properties: Comma-separated property names to return. Available: ObjectId, X, Y, X1, Y1, X2, Y2, Layer, Net, Width, Name, Rotation, HoleSize, TopXSize, TopYSize, Size, Pattern, SourceDesignator, Text, Descriptor, Selected Returns: Dictionary with "objects" array and "count" |
| pcb_set_layer_visibilityB | Show or hide a specific PCB layer. Args: layer: Layer name string, e.g.: Copper: "TopLayer", "BottomLayer", "MidLayer1"-"MidLayer30" Overlay: "TopOverlay", "BottomOverlay" Mask: "TopPaste", "BottomPaste", "TopSolder", "BottomSolder" Plane: "InternalPlane1"-"InternalPlane16" Other: "DrillGuide", "DrillDrawing", "MultiLayer", "KeepOutLayer", "Mechanical1"-"Mechanical16" visible: True to show, False to hide Returns: Dictionary with layer name and visibility state |
| pcb_repour_polygonsA | Repour every poured polygon on the open PCB, in pour order. Each polygon is rebuilt through the API, so a changed clearance
or board-edge rule takes effect. Shelved polygons stay shelved.
Returns:
|
| pcb_set_board_shapeA | Define the physical PCB board outline as a rectangle. Overwrites the current board shape. Use this right after creating a new PCB document to establish the board size before placing parts. Coordinates are in mils; (x1,y1) and (x2,y2) are opposite corners in any order. Args: x1: First corner X in mils y1: First corner Y in mils x2: Opposite corner X in mils y2: Opposite corner Y in mils Returns: Dictionary confirming the new outline rectangle |
| pcb_place_polygon_rectA | Drop a copper polygon pour on a rectangular area. Useful for placing a ground plane or power plane: pass the board's corners, the layer, and the net name (typically "GND"). Set pour_over=False to force the pour around same-net tracks/pads instead of covering them. Args: x1: First corner X in mils y1: First corner Y in mils x2: Opposite corner X in mils y2: Opposite corner Y in mils net: Net name to assign (empty = no-net fill, unusual) layer: Copper layer (default "TopLayer") pour_over: Pour over same-net objects (default True) Returns: Dictionary confirming the polygon placement |
| pcb_place_via_arrayA | Stitch vias in a regular grid across a rectangle. Typical use: GND stitching between top and bottom layer copper pours. Places vias at every (pitch × pitch) grid intersection inside the rectangle. Args: x1: First corner X in mils y1: First corner Y in mils x2: Opposite corner X in mils y2: Opposite corner Y in mils pitch: Grid spacing in mils (default 50) net: Net to assign (typically "GND"; empty = no net) size: Via pad diameter in mils (default 30) hole_size: Drill hole diameter in mils (default 12) low_layer: Start layer (default "TopLayer") high_layer: End layer (default "BottomLayer") Returns: Dictionary with count of vias placed and rectangle/pitch echo |
| pcb_place_viaA | Place a via at specific coordinates on the active PCB. Sizes take fractions of a mil, or millimetres through Args:
x: Via X position in mils
y: Via Y position in mils
net: Net name to assign (optional, empty = no net)
size: Via pad diameter in mils (default 50)
hole_size: Drill hole diameter in mils (default 28)
low_layer: Start layer (default "TopLayer")
high_layer: End layer (default "BottomLayer")
size_mm: pad diameter in mm, used instead of Returns: Dictionary with placed via position and size (mils) |
| pcb_place_tracksA | Place many track segments on the active PCB in ONE IPC round-trip. PREFER THIS over placing one segment at a time whenever you have more than one segment to place. The whole batch is wrapped in a single PreProcess/PostProcess and a single save, so 50 tracks take roughly the same wall time as 1. Typical uses: routing a full net, laying down a whole stitch pattern, replicating a motif, drawing a keepout rectangle. Args: tracks: List of track dicts. Each dict supports: x1, y1, x2, y2 (required, mils; decimals are kept) width (default 10, mils; decimals are kept, so a 0.1 mm rule stays 3.937), layer (default "TopLayer"), net_name (optional, empty = no net) Returns: Dictionary with "placed" and "failed" counts |
| pcb_place_viasA | Place many vias on the active PCB in ONE IPC round-trip. PREFER THIS over Args: vias: List of via dicts. Each dict supports: x, y (required, mils), size (default 50), hole_size (default 28), low_layer (default "TopLayer"), high_layer (default "BottomLayer"), net (optional, empty = no net) Returns: Dictionary with "placed" and "failed" counts and "unknown_layers" naming any layer pair that did not resolve. |
| pcb_place_arcA | Place an arc on the active PCB. Creates a circular arc segment defined by center, radius, and angular range. Args: x_center: Arc center X position in mils y_center: Arc center Y position in mils radius: Arc radius in mils start_angle: Start angle in degrees (default 0) end_angle: End angle in degrees (default 360 = full circle) width: Arc line width in mils (default 10) layer: PCB layer name (default "TopLayer") Returns: Dictionary with placed arc geometry and layer |
| pcb_place_textA | Place a text string on the active PCB. Args:
text: Text content to place
x: Text X position in mils
y: Text Y position in mils
layer: PCB layer name (default "TopOverlay"). Common choices:
"TopOverlay", "BottomOverlay", "TopLayer", "BottomLayer",
"Mechanical1"-"Mechanical16"
height: Text height in mils (default 60), decimals allowed
rotation: Rotation angle in degrees (default 0)
stroke: Stroke width in mils; 0 keeps Altium's default.
To resize existing designators use Returns: Dictionary with placed text properties, height and stroke as read back from the placed text |
| pcb_place_fillA | Place a rectangular copper fill on the active PCB. Creates a solid copper rectangle. Useful for thermal pads, ground planes, and copper pours in specific areas. Args: x1: First corner X in mils y1: First corner Y in mils x2: Second corner X in mils y2: Second corner Y in mils layer: PCB layer name (default "TopLayer") net_name: Net name to assign (optional, empty = no net) Returns: Dictionary with placed fill coordinates and layer |
| pcb_start_polygon_placementA | Start INTERACTIVE polygon pour placement on the active PCB. This is an interactive command, it launches Altium's polygon placement mode. The user must then draw the polygon boundary interactively in Altium Designer (clicks define vertices, right-click or Escape completes). It does NOT create a polygon programmatically from coordinates. Args: layer: Target copper layer (default "TopLayer") net_name: Net to assign to the polygon pour (optional) Returns: Dictionary confirming polygon placement mode was initiated |
| pcb_create_design_ruleA | Create a new design rule on the active PCB. Args:
name: Rule name (e.g., "Min Clearance 6mil").
rule_type: Type of rule to create. Options:
Returns: Dictionary with created rule details. Note: Creating ComponentClearance, HoleToHoleClearance,
BoardOutlineClearance, and other newer rule kinds is not
supported on this Altium build because the relevant symbolic
constants (eRule_ComponentClearance, ...) are not exposed in
DelphiScript. Existing rules of those kinds can be UPDATED via
|
| pcb_delete_design_ruleC | Delete a design rule by name from the active PCB. Args: name: Exact name of the design rule to delete Returns: Dictionary confirming deletion |
| pcb_get_component_padsA | Get all pads of a specific PCB component. Returns detailed pad information including pin name, position, net assignment, size, and hole information. DATASHEET DISCIPLINE: Pad name -> pin function mapping comes
from the footprint, which can be wrong (especially the thermal
pad on QFN/DFN, which is rarely numbered consistently across
vendors). Before stating which pin a pad corresponds to,
cross-check the manufacturer datasheet's mechanical /
recommended-land-pattern section. The response carries
Args: designator: Component reference designator (e.g., "U1", "J3") Returns:
Dictionary with "designator", "pads" array (each with name,
x, y, net, layer, hole_size, top_x_size, top_y_size,
rotation), "pad_count", plus |
| pcb_flip_componentB | Flip a component to the other side of the board (top to bottom or bottom to top). Args: designator: Component reference designator (e.g., "U1", "R5") Returns: Dictionary with designator, old_layer, and new_layer |
| pcb_align_componentsB | Align multiple PCB components along a common edge or center. Args: designators: Comma-separated component reference designators (e.g., "R1,R2,R3,R4") alignment: Alignment mode. Options: "left" - Align to leftmost X "right" - Align to rightmost X "top" - Align to topmost Y "bottom" - Align to bottommost Y "center_x" - Center horizontally "center_y" - Center vertically Returns: Dictionary with alignment result and component count |
| pcb_snap_to_gridA | Snap a component to the nearest grid point. Rounds the component's X and Y position to the nearest multiple of the specified grid size. Args: designator: Component reference designator (e.g., "U1", "R5") grid_size: Grid spacing in mils (default 50) Returns: Dictionary with designator, old and new positions, and grid_size |
| pcb_get_diff_pair_rulesA | Get all differential pair routing rules from PCB design rules. Returns design rules of kind eRule_DifferentialPairsRouting, these are routing rules, NOT IPCB_DifferentialPair pair objects on the board. Returns: Dictionary with "diff_pair_rules" array (each with name, enabled, scope_1, scope_2, comment, descriptor) and "count" |
| pcb_get_viasA | Get all vias on the active PCB board. Returns via position, pad size, hole size, net assignment, and start/end layer for every via on the board. Returns: Dictionary with "vias" array (each with x, y, size, hole_size, net, low_layer, high_layer) and "count" |
| pcb_calc_polygon_areaA | Report the area of each copper polygon on the active board. Returns each polygon's overall boundary area in square mils and square millimetres, optionally filtered by net and/or layer. Useful for estimating copper coverage / plane area. Args: net: Only polygons on this net (optional). layer: Only polygons on this layer name (optional). Returns:
Dict with |
| pcb_set_via_soldermask_reliefA | Open the solder mask round each via's barrel, measured from the hole edge, on both sides. Every via, or those on WRITTEN THROUGH THE VIA'S PAD CACHE. Assigning the expansion straight onto a via crashes Altium's scripting engine (an access violation in ScriptingSystem.DLL, measured on AD 26.10); the same value written into the cache a via shares with pads takes and reads back, so the handler only ever uses that route. A Solder Mask Expansion rule scoped Args: expansion_mils: Mask expansion from the hole edge, in mils. Default 4. net: Only vias on this net. Empty means every via. Returns:
|
| pcb_get_mech_layer_namesA | Every enabled mechanical layer on the board, and what is on it. WHAT IS ON THE LAYER IS THE PART YOU CANNOT GET ELSEWHERE. A
PcbLib header carries USEDBYPRIMS; a PcbDoc does not, so on a
board there is no way to ask which mechanical layers the
geometry occupies. This counts, because moving kinds around on a
board you cannot inspect is how an assembly drawing gets
orphaned. ENABLED, NOT DISPLAYED. This used to list only layers the view
happened to be showing, so a layer carrying the whole fab
drawing was missing from the answer whenever it was toggled off.
Display is a view setting and is reported separately as
Each entry carries its Args: count_primitives: Count what sits on each layer. The board is walked once per enabled layer, so pass False when only the names are wanted. Returns:
Dict with |
| pcb_set_mech_layersA | Name, enable and kind the mechanical layers of the open BOARD. The board counterpart of Every change is READ BACK. A layer whose name, enable or kind did not take is reported against that layer rather than folded into an overall pass. PAIRED KINDS. Any kind ending in Top or Bottom is held by the layer PAIR rather than by either layer, under a shorter name with the side dropped, so "Courtyard Top" is stored as the pair kind "Courtyard". Give both sides in the same call and the two are joined and the pair given the kind. Single kinds such as "Fab Notes" need no partner. READ THE BOARD FIRST. Args:
layers: One dict per layer. Keys: Returns:
Dict with |
| pcb_get_layer_displayA | Visibility and colour for every layer on the active board. Covers signal, plane, mechanical, mask, paste, silk, keepout and
multilayer. Each entry gives the internal Read this before recolouring: Altium stores a colour as a Windows TColor, which is byte-reversed against the #RRGGBB people write, and getting that backwards produces a plausible wrong colour rather than an error. Returns:
Dict with |
| pcb_set_layer_colorA | Recolour one layer. The colour is given as The write is READ BACK before reporting success, because a refused assignment raises nothing and would otherwise be reported as having worked. Colour is a display setting rather than a property of the board, so it follows the installation rather than travelling with the file. Args: layer: Layer name, e.g. "TopOverlay" or "Mechanical13". color: Colour as "#RRGGBB". Returns:
Dict with |
| pcb_set_mech_layer_kindA | Set what a mechanical layer is FOR, not what it is called. Renaming a layer "Courtyard Top" does not make it one. The KIND is a separate property, and it is what every feature resolving a layer by purpose reads: courtyard checking, assembly drawings, 3D body placement and the IPC-4761 via treatments. A layer with no kind is skipped by all of them, so the outlines get drawn and nothing uses them. A SINGLE kind such as "Fab Notes" belongs to ONE layer at a time.
If another layer already holds it, that layer is cleared first and
named in A PAIRED kind, meaning any name ending in Top or Bottom, works
differently: it is held by the layer PAIR rather than by either
layer, under a separate set of names with the side dropped. So
"Courtyard Top" is stored as the pair kind "Courtyard" across the
two layers, and The write is READ BACK before reporting success. A refused assignment raises nothing here, so trusting it would report success for having changed nothing. Args:
layer: Mechanical layer, e.g. "Mechanical13".
kind: A kind name such as "Courtyard Top", "Assembly Top",
"3D Body Top", "Component Outline Top", "Fab Notes" or
"Not Set". A bare number is also accepted, so a kind added
by a later Altium release can be set without waiting for
the name map to catch up. Read the current assignment with
Returns:
Dict with |
| pcb_delete_objectA | Delete a PCB object closest to specific coordinates on a layer. Finds the nearest matching object within 100 mils of the given coordinates and removes it from the board. Distance is to the object itself: a track by its segment less half its width, an arc by its curve, a via by its centre less its radius, anything else by its bounding rectangle (0 inside it). A point anywhere on a track finds that track. Args:
x: Target X position in mils
y: Target Y position in mils
layer: PCB layer name (default "TopLayer")
object_type: Type of object to delete. Options:
"track" - Track segment
"via" - Via
"fill" - Copper fill
"text" - Text string
"pad" - Free pad
"arc" - Arc
"polygon" - Copper polygon pour
"region" - Region / split-plane
"component" - Placed component
(for bulk/filter-based deletes use Returns: Dictionary with deleted status, object_type, distance_mils, the deleted object's net and bbox_mils, and others_as_close: how many other objects were exactly as near, so a pick among equals is visible. |
| pcb_get_pad_propertiesA | Get detailed pad information filtered by net or component. Returns pad shape, size, hole, thermal relief, and solder/paste mask expansion details. Provide at least one filter (net or designator) to avoid returning all pads on the board. Args: net: Filter by net name (e.g., "GND", "VCC"). Optional. designator: Filter by component designator (e.g., "U1"). Optional. Returns: Dictionary with "pads" array (each with name, component, x, y, net, layer, shape, top_x_size, top_y_size, hole_size, rotation, is_smd, solder_mask_expansion, solder_mask_bottom_expansion, solder_mask_separate, paste_mask_expansion) and "count". solder_mask_expansion is the TOP side when solder_mask_separate is true and both sides when it is false; the bottom value is stored either way and takes effect once the sides are unlinked. Expansions read 0 when the pad follows the board's rule. |
| pcb_set_track_widthA | Modify track width for all tracks on a specific net. Changes the width of every routed track segment assigned to the given net. Useful for adjusting power or signal trace widths. Args: net_name: Name of the net whose tracks to modify (e.g., "VCC") width_mils: New track width in mils (e.g., 10, 20, 50) Returns: Dictionary with net_name, width_mils, and tracks_modified count |
| pcb_get_unrouted_netsA | Get list of nets with unrouted connections (ratsnest lines). Identifies nets that still have ratsnest lines, meaning they are not fully routed. Useful for checking routing completion status. The count is of the connection lines stored on the board, and
those can be out of date: boards whose nets were all joined have
been reported with open connections. Args: reanalyze: re-derive the ratsnest before counting (default False). Returns: Dictionary with "unrouted_nets" array (each with net name and unrouted_connections count), "net_count", "total_unrouted" and "reanalyzed" |
| pcb_get_polygonsA | Get all polygon pours on the active PCB with copper area. Each polygon row carries:
Pair with Returns:
Dict with |
| pcb_modify_polygonA | Modify a polygon pour's properties and its pour options. Changes net, layer, hatching style, or the three "remove" options
from the Polygon Pour dialog. Use NOTHING HERE REPOURS. The pour options and the hatch style decide
what the NEXT pour produces, so the board does not change until
Args:
index: Polygon index (from pcb_get_polygons output)
net: New net name to assign (optional, empty = no change). A
name that matches no net on the board is reported under
Returns:
|
| pcb_place_3d_bodyA | Place a STEP model directly on the open PCB, as a free 3D body. The equivalent of Altium's Place > 3D Body > Generic STEP Model: the model lands on the document itself, not inside a component. USE THIS RATHER THAN Rotation cannot be set from here. Args: model_path: absolute path to the .step / .stp file. x: body origin X in mils. This is the model's own origin, so where it lands depends on how the STEP was authored; check it against a known feature such as a silkscreen outline rather than assuming it is centred. y: body origin Y in mils. layer: board layer to attach it to. Default TopLayer. standoff_height: height in mils of the body's underside above the board. 0 sits it on the surface. Returns:
|
| pcb_get_room_rulesA | Get all room-like rules (confinement constraint design rules). Returns design rules of kind eRule_ConfinementConstraint, these are NOT physical IPCB_Room objects on the board. The rule bounding rect is reported as x1/y1/x2/y2 in mils. Returns: Dictionary with "room_rules" array (each with name, enabled, kind, scope_1, comment, x1, y1, x2, y2) and "count" |
| pcb_create_roomA | Create a room for component grouping on the active PCB. Creates a confinement constraint rule that defines a rectangular region. Components can be assigned via scope expression. Args: name: Room name (e.g., "Power Section", "USB Block") x1: First corner X in mils y1: First corner Y in mils x2: Second corner X in mils y2: Second corner Y in mils components: Comma-separated component designators to confine (e.g., "U1,U2,R1,R2"). Optional; empty = applies to all. Returns: Dictionary with created status, name, coordinates, and scope |
| pcb_get_board_statisticsB | Get comprehensive statistics for the active PCB board. Returns counts of all object types, total trace length, board dimensions, and layer count. Useful for design reviews and progress tracking. Returns: Dictionary with track_count, via_count, pad_count, component_count, fill_count, text_count, polygon_count, unrouted_connections, total_trace_length_mils, board_width_mils, board_height_mils, board_area_sq_mils, layer_count, and board_name |
| pcb_export_coordinatesA | Export component placement coordinates formatted for pick-and-place (like Returns designator, footprint, comment, position (x, y), rotation, layer, and side (Top/Bottom) for every component. Useful for manufacturing pick-and-place machine programming. Returns: Dictionary with "placements" array (each with designator, footprint, comment, x, y, rotation, layer, side) and "count" |
| pcb_create_diff_pairA | Create a differential pair object from two existing nets. The two nets must already exist on the board (typically present after update_pcb / ECO). The diff-pair object lets Altium apply differential routing constraints and the interactive router to honour impedance / matched-length rules between the pair. Args: positive_net: Positive-side net name (e.g. "USB_DP") negative_net: Negative-side net name (e.g. "USB_DM") name: Optional diff-pair name (defaults to "_") Returns: Dictionary confirming creation with name, positive_net, negative_net |
| pcb_place_regionA | Place a solid copper region on a rectangular area. Regions are solid primitives; unlike polygons, they don't participate in the connectivity engine unless you assign a net. Use for mechanical copper zones, thermal pads, or solder-mask openings. For a true ground plane with ratsnest tracking, prefer pcb_place_polygon_rect. Args: x1, y1, x2, y2: Opposite corners in mils (any order) layer: Copper or mech layer (default "TopLayer") net: Optional net assignment Returns: Dictionary confirming the region placement |
| pcb_place_dimensionA | Place a linear dimension between two points. Horizontal dimension measures delta-X, vertical measures delta-Y. Orientation auto-detects from the larger axis delta if not given. Args: x1, y1: First reference point in mils x2, y2: Second reference point in mils layer: Layer to draw the dimension on (default "TopOverlay") orientation: "horizontal" or "vertical" ("" = auto) Returns: Dictionary confirming the dimension placement |
| pcb_place_padA | Place a standalone pad on the active PCB. Not part of any component. Use for fiducials, test points, mounting holes. Set hole_size=0 for surface-mount pads, nonzero for through-hole. Args: x, y: Position in mils name: Pad designator / label (optional) net: Net to connect to (optional) shape: "round" (default) / "rect" / "oct", or spelled out as the library tools take them ("rectangular", "octagonal"). Any other word is refused; it used to become a round pad. x_size, y_size: Pad dimensions (default 60 mil) hole_size: Drill diameter (0 = SMD) layer: Copper layer (default "TopLayer") units: "mil" (default) or "mm", for the position and every size, kept exact rather than rounded to whole mils. Returns: Dictionary confirming pad placement |
| pcb_place_componentsA | Place one or many footprints from PcbLibs onto the board in ONE call. The scriptable substitute for ECO / Design ▸ Update PCB Document: Altium's ECO always raises a modal, so for unattended population this drops footprints straight onto the board. It resolves the board once and places every footprint in a single Altium transaction (one IPC round-trip). Pass a single-element list to place just one. Two modes per component: geometry only (omit
Args:
placements: List of placement dicts, each with:
footprint (required), library_path (required, .PcbLib),
x, y (mils), designator, lib_reference, comment,
rotation, layer, unique_id, and pad_nets
( Returns:
Dict with |
| pcb_place_angular_dimensionA | Place an angular dimension (angle between two reference directions). Args: center_x, center_y: Vertex of the angle in mils x1, y1: First reference direction endpoint in mils x2, y2: Second reference direction endpoint in mils radius: Arc radius at which to draw the dimension in mils layer: Layer (default "TopOverlay") Returns: Dictionary confirming the angular dimension |
| pcb_place_radial_dimensionB | Place a radial dimension around a center point with a given radius. Args: center_x, center_y: Center point in mils radius: Radius to dimension in mils layer: Layer (default "TopOverlay") Returns: Dictionary confirming the radial dimension |
| pcb_distribute_componentsA | Evenly space components along an axis. Moves each named component so its X (or Y) coordinate lands at
equally-spaced stops from Args: designators: Comma-separated list of component designators axis: "x" or "y" (default "x") start: First position in mils end: Last position in mils Returns: Dictionary with distribution result |
| pcb_get_rule_propertiesA | Read properties of a named PCB design rule. Returns metadata (name, rule_kind, enabled, priority) plus a
WHY THE DESCRIPTOR AND NOT THE NUMBERS. Constraint values live on per-kind subtype interfaces (IPCB_ClearanceConstraint, IPCB_MaxMinWidthConstraint, ...). This handler holds a base IPCB_Rule, where those members do not exist, so reading them gives nothing and the descriptor is what is offered instead. Parse it client-side if you need numeric values. THAT IS A LIMIT OF THIS READ, NOT OF THE API, and the difference
matters because the sentence above has already been read as
"constraints are unreachable" and stopped someone who then
reported a rule as unwritable. DelphiScript DOES narrow an
interface, but only at iterator return, so a typed local
assigned straight from A clearance-family rule also returns Args: name: Design rule name (e.g., "Clearance", "Width", "RoutingVias"). Returns: Dict with name, rule_kind, enabled, priority, descriptor, and gap_mm for a clearance-family rule. |
| pcb_set_rule_propertiesA | Update metadata AND constraint values of a named PCB design rule. Metadata fields always apply. Constraint fields are dispatched by the rule's underlying RuleKind:
THE GAP WRITE IS READ BACK, not assumed. A rule kind that does
not really carry Gap can accept the assignment and keep its old
value, so the reply carries Pass only the parameters you want to change; everything else
stays untouched. Each VERIFIED field write increments
NOTE: Priority is NOT writable from this tool. Args:
name: Rule name to update.
enabled: Whether DRC enforces the rule.
scope1 / scope2: Rule scope query expressions. A comparison
joined by And/Or/Xor/Not must be bracketed
( Returns: Dict with name, rule_kind, and properties_updated count. |
| pcb_place_embedded_boardA | Place an embedded-board array (panel) referencing a child PCB. An embedded board is a grid of copies of a child .PcbDoc file, used for panelization (multi-up arrays, step-and-repeat). Args: child_path: Full path to the child .PcbDoc file. x, y: Bottom-left corner of the array in mils. rows, cols: Grid size (default 1x1). row_spacing_mils, col_spacing_mils: Gap between array cells. mirror: Flip the child board over when True. layer: Placement layer for the embedded-board primitive. Returns: Dict with success, child_path, rows, cols, x, y. |
| design_review_snapshotA | Fetch a comprehensive design-review snapshot in ONE tool call. THIS -- the compiled netlist + part data it returns -- is the
BASIS of a design review, not a render. Judge connectivity, part
values, ratings, and pin functions from these sections (and the
cited datasheets), never from PREFER THIS over running 8-12 individual review queries. A normal review (components, nets, rules, diff, messages, stats, unrouted, BOM) is one round-trip instead of one LLM turn per section. That's the single biggest time cost on a full review. CRITICAL, datasheet discipline (enforced via _review_guidance): Before drawing ANY conclusion about a component's pin function, voltage rating, or electrical spec, fetch the actual manufacturer datasheet and verify. The schematic symbol, footprint, and parameter fields are NOT ground truth - they are often wrong or outdated. Every proposed fix must cite the datasheet section or page you relied on. The response's CRITICAL, review-quality discipline (enforced via _review_guidance): A finding must ADD analysis the raw sections do not. Run ERC and DRC, but do NOT relay their raw output as findings - investigate each violation after the datasheet review, drop the false positives, and surface the real ones as specific, traced findings (a genuine ERC/DRC violation can be a top finding - never dropped). Do NOT emit "verify X" / "confirm X" as a finding - that hands the analysis back to the user. Every finding names the exact parts/pins/nets, is backed by a netlist fact or a cited datasheet, states a concrete consequence and fix, and is something you would raise in a real design review. The full rules are in _review_guidance["review_quality_rules"]. Args: sections: Which snapshot sections to include. Defaults to the standard review set (project_info, design_stats, components, nets, design_rules, unrouted, diff, messages, board_stats, fab_stats). Available extras: "bom", "drc", "erc", "unconnected_pins", "project_options". include_bom: Convenience - adds "bom" to sections if True (default). BOM is the best source of manufacturer part numbers for datasheet lookup. run_drc: If True, runs DRC (slow, 30-90 s) and includes results. Off by default - assume the user already ran it, or run it separately when asked. run_erc: If True, runs ERC and includes results. Off by default. force_recompile: SaveAll + invalidate SmartCompile cache + recompile before gathering any sections. Use this when the user has been editing schematics in the Altium UI and you need a guaranteed-fresh netlist. Costs one extra ~5-10 s compile up-front. Returns: Dict with one key per requested section, plus: - _review_guidance: datasheet + review-quality rules Claude must follow when turning sections into findings - _unique_parts: list of {manufacturer, part_number, designators} to fetch datasheets for - _sections_failed: sections that errored (partial results are still usable) |
| design_lint_reportA | Run all design-lint checks and return a consolidated violation report. Sequences the individual Returns structured JSON instead of dumping to the Messages panel (Altium's panel is fine for human review but the agent needs a machine-readable shape). Checks executed:
Args:
run_drc: If True, also runs Altium's DRC and includes its
violations. Off by default because DRC mutates the .DRC
report file and can take ~5-10s on a busy board.
bad_connection_tolerance_mils: Coord tolerance for
Returns:
Dict with:
- |
| design_datasheet_checklistA | Return the datasheet-first discipline checklist for design review. Use this when you need the rules without pulling the full snapshot. The rules also ship inside the _review_guidance block of design_review_snapshot - no need to call this separately if you already ran a snapshot. Returns: Dict with datasheet_rules (list of rules) and a short action_required summary. |
| sim_get_readinessA | Audit every component on the active schematic for SPICE readiness. Use this as step 1 of any simulation workflow. The response classifies each component into one of three buckets:
CRITICAL, vendor SPICE models only:
Never fabricate a SPICE model from datasheet reasoning. The
parameters that matter for convergence, bias point, and
small-signal behavior are not in any datasheet summary; a
plausible-looking hand-rolled model produces confidently-wrong
simulation results. The response's Returns: Dict with: - ready, ready_count - needs_primitive, needs_primitive_count (each entry has designator, comment, suggested_prefix, suggested_value) - needs_file, needs_file_count (each entry has designator, comment, lib_ref, manufacturer, manufacturer_part) - _spice_guidance (rules + structured search_hints + primitive_hints) |
| sim_attach_modelA | Attach an external SPICE model file (.mdl / .ckt / .lib) to a component. Use this after fetching a vendor SPICE model file from the
manufacturer and saving it locally. The model_name parameter
must be the exact Args:
designator: Component reference (e.g. "U1").
file_path: Full path to the locally-saved .mdl / .ckt / .lib.
model_name: Subcircuit / model name declared inside the
file. Open the file and look for Returns: Dict with success, designator, file_path, model_name. |
| sim_runA | Run Altium's mixed-signal simulation of the focused project. Runs the analyses set up for the project: with sim_setup_analysis, or in Altium's Simulation Dashboard. A run started from a script performs an operating point, DC sweep, transient and AC together (MEASURED: the dashboard's on/off switches are not honoured). It succeeds only when the run produced its results document (a .sdf, opened in its own tab), and fails with SIM_NOT_RUN when nothing appeared. The results are saved and read back: the reply carries each analysis's waves with min, max, first and last, and sim_get_results gives the traces. Typical workflow: 1. Activate one of the project's schematic sheets. 2. Use sim_get_readiness + sim_attach_* to make sure every component has a SPICE model. 3. Place probes on measurement nodes with sch_place_probe. 4. Set the analyses with sim_setup_analysis. 5. Call sim_run, then sim_get_results for the traces. Args: analysis: Free-form label echoed back in the response. Does not drive Altium, the project's setup does. Returns: Dict with success, ran, results_document (the .sdf path), results_saved, results (per analysis, per wave: unit, points, min, max, first, last; magnitude for an AC wave), analysis and note. |
| sim_setup_analysisA | Set the analyses sim_run will use, in the project's .simcfg. Values are SPICE values: a number in SI units, or a string with a SPICE suffix ("5u", "10n", "1k", "100meg"). Args: transient: {"stop", "step", "start" (default 0), "max_step" (default step)}. ac: {"start", "stop", "points", "sweep": "dec" | "oct" | "lin"}. Points are per decade or octave, or in total for lin. dc: {"source" (a source designator such as "V1", or "Temp"), "start", "stop", "step"}. outputs: expressions to plot in each analysis set here, e.g. ["v(out)", "i(v1)"]. project_path: the project; empty uses the focused one. WHAT A RUN DOES, MEASURED: a run started from a script performs an operating point, a DC sweep, a transient and an AC analysis together, whatever is switched off in the dashboard. The values set here are what those analyses use. An analysis you do not need still runs on its last settings; sim_get_results(analysis=...) returns just the one you want. Altium's own settings are saved first, so changes made in the Simulation Dashboard are kept, then the file is changed and reloaded into Altium. A project without a .simcfg gets one. Returns: Dict with simcfg (the file), set (the keys written), reloaded, and created when the file is new. |
| sim_get_resultsA | Read a simulation's results: every wave, with sampled points. Reads the .sdf that sim_run saved (the last one by default). Each wave comes with its unit, point count, min/max/first/last over every point, and up to max_points samples evenly spaced from first to last. An AC wave reports magnitude and phase in degrees against frequency. The sweep variable (time, frequency, the swept source) is marked independent. Args: results_document: path of a .sdf; empty uses the last sim_run. analysis: one analysis by name ("Transient Analysis", "AC Analysis", "Operating Point", "DC Sweep", ...); empty returns all. waves: wave names to keep, e.g. ["v(out)", "i(v1)"]; empty keeps all. max_points: samples per wave; 0 returns statistics only. all_runs: a document run more than once holds every run; by default only the latest run of each analysis is returned. Returns: Dict with results_document and analyses: a list of {analysis, waves: [...]}, or an error naming what is missing. |
| design_get_disciplineA | Read the design discipline + DesignPlan JSON schema. ALWAYS call this first when starting a design task. The result
contains the hard rules the planner must follow (net-label-driven
wiring, datasheet-first part choice, NDA isolation, etc.) plus
the JSON schema that Returns:
A dict with |
| design_session_startA | Open a durable design-session journal for an autonomous run. The journal is append-only state that survives context compaction,
client restarts, and model switches, so any later client can resume
the run from recorded fact instead of chat history. Call this once at
the start of a spec-to-board task, then log stage results as you go
and read Args: requirement: the design requirement text this run implements. session_id: optional explicit id; defaults to a timestamp. Returns:
|
| design_session_logA | Append one event to a design-session journal.
|
| design_session_statusA | Read a design session's derived state (stage map, artifacts, ...). With no |
| design_session_resumeB | Resume a design run: state plus a plain-language next-action hint. Surfaces any open blocking question first (answer it before proceeding), otherwise names the next pipeline stage to work on. Use this at the start of a fresh client session to pick up where the last one stopped. |
| design_next_actionA | Decide the single next action for an autonomous design run. Reads the session journal and returns the next 13-stage pipeline step
server-side, so a client need not memorize the workflow: loop
"call design_next_action -> do what it says -> design_session_log the
result" until Returns a dict with The layout stages (placement, routing, pours_tuning, verification)
have measured gates: the reply also carries |
| design_autonomy_guideA | The autonomous spec-to-board loop protocol, in one call. Returns how to drive a full design run with the harness: the loop
(start session → design_next_action → execute → log → repeat), the
13 pipeline stages with their tools and exit gates, the hard
constraints, and how to resume after context loss. Read this once
before an autonomous run; |
| design_session_reportA | Write up a design run from its session journal, as markdown. Assembled only from what the run recorded: the requirement, each
stage's outcome with the gate numbers logged for it, decisions,
audit results, simulations and open issues. The body sections come
in a fixed order: placement strategy, stack-up and impedance,
critical routes (lengths, skews, layer changes, return vias,
exceptions), power paths, planes and fan-out (where via-in-pad was
used and why), silkscreen policy, verification results, simulations,
open issues. A section nothing was logged for says so in one line.
Notes reach a section through their Args: session_id: the session to report; blank uses the most recently active one. output_path: also write the markdown to this file. Its folder must exist, and a path inside the installed eda_agent package is refused. Blank writes nothing. Returns:
|
| pcb_layout_auditA | Measure a board for the layout stages' exit gates. Changes nothing. Reads the focused board exactly, the way
Log the result as Args:
checks: names from the list above; None runs them all.
expect_file: full path of the focused board, for a live read.
The read refuses on the first reply if another board is
focused.
board_json_path: a saved LayoutBoard (.json or .json.gz) to audit
offline instead; nothing is read from the editor.
nets: the signal nets Returns:
|
| design_job_startA | Start a long engine run as a background job; returns its id. For work that can exceed the MCP tool timeout (routing a dense
board). Poll Args:
kind: registered job kind. Currently: Returns:
|
| design_job_statusA | Status of a background job (or all jobs if |
| design_job_resultB | Fetch a finished job's result payload (None until it's done). |
| design_snapshot_inventoryA | Open a list of SchLib files and return what components live in them. NDA scope: only pass paths to the user's own neutral standard libraries. Do NOT pass project-local library paths from another client engagement, design knowledge cannot cross NDA boundaries. Large libraries (passives/connectors can hold hundreds of parts)
easily exceed the tool-output token budget, so the RETURNED set is
filtered and capped. The FULL inventory is always cached to
Args:
library_paths: Absolute paths to .SchLib files to scan.
name_filter: Case-insensitive substring; keep only components
whose lib_ref or description contains it (e.g. Returns:
Inventory dict: |
| design_validate_planA | Validate a candidate DesignPlan JSON against the schema + cross-check. Run this before Args: plan_json: Either a JSON string of the DesignPlan, or the DesignPlan as a JSON object/dict. The MCP framework auto-deserializes JSON-object literals to dicts before the tool sees them, so both shapes are accepted. Returns:
|
| design_list_circuit_blocksA | List the canonical circuit blocks and their parameter contracts. Discoverability for Returns:
|
| design_add_circuit_blockA | Fold a canonical circuit block into a DesignPlan in one call. Authoring boilerplate sub-circuits pin-by-pin in plan JSON is slow
and error-prone (a decoupling network is N caps, 2N pins, and two
net merges that must line up). This emits the canonical topology
of a common block and wires it into It is naming-agnostic: it owns the wiring pattern, never the
part choice. YOU supply every part identity in Blocks and their required
Call Net endpoints the block does NOT own (a pullup's signal, an RC input, a divider rail) should already exist in the plan; the block only creates the nets it fully populates. If you point a block at a net that ends up with a single pin, the inline ERC reports it as a floating net for you to complete. Args: plan_json: the DesignPlan as a JSON string or dict. block: block name (see the list above). params: block parameters (see per-block requirements above). Returns:
|
| design_add_partA | Add one part and wire its pins to named nets, in one call. The atomic authoring primitive under the block/bus tools: place a
single arbitrary part -- an MCU, a connector, a regulator -- and
fold each pin into a net. Naming-agnostic: you supply the part identity and net names chosen from the live inventory; this owns only the pin->net folding. Args:
plan_json: the DesignPlan as a JSON string or dict.
refdes: the new part's designator (must be free in the plan).
lib_ref: its library symbol name.
connections: Returns:
|
| design_connect_busA | Wire a parallel bus across two+ parts in one call. A wide interface -- an 8-bit data bus between an MCU and a display, an address bus to a memory -- is otherwise N near-identical net objects where bit i of one side is easily misaligned with bit i+1 of the other. This joins the i-th pin of every endpoint into one net per bit, so alignment is structural and the whole bus is one call. It creates NO parts: the endpoints reference parts already in the plan. The nets share one part-set -- the signature the pipeline uses to DRAW a >=4-bit bus as a bus glyph automatically. Args:
plan_json: the DesignPlan as a JSON string or dict.
endpoints: one dict per part on the bus, Returns:
|
| design_compose_netlistA | Apply many authoring operations to a plan in ONE call. The bulk form of the authoring primitives -- the same reason you prefer a batch Altium tool over looping the singular one. Instead of one round-trip per part/block/bus, pass an ordered list and this threads the plan through all of them, then validates once. Each operation sees the previous one's result, so a part added early is available to a bus wired later. Build a whole board in a single call. Args:
plan_json: the DesignPlan as a JSON string or dict.
operations: ordered list of op dicts, each with an Returns:
|
| design_generate_bomA | Derive the bill of materials from a plan's parts in one call. Every design needs a BOM, and it is mechanical to build from parts
you already authored -- this rolls them up so you do not hand-group
refdes (redundant with the parts, and easy to miscount). Parts with
an
Args:
plan_json: the DesignPlan as a JSON string or dict.
set_on_plan: when True (default), the returned Returns:
|
| design_edit_planA | Edit an existing plan -- the MODIFY complement to the add tools. Authoring is iterative: a review turns up a wrong value, a part to drop, two nets that should be one. Fix it with edits instead of re-emitting the whole plan, and let the tool own the error-prone bookkeeping (deleting a part scrubs it from every net; merging nets moves and de-dupes pins). Ordered ops, each sees the previous result; validates once at the end so a now-floating net surfaces. Operations (each a dict keyed by
Args: plan_json: the DesignPlan as a JSON string or dict. operations: the ordered edit ops. Returns:
|
| design_compute_component_valueA | Compute a manufacturable component value, snapped to an E-series. Use this instead of doing the arithmetic by hand: it applies the
standard sizing equation, snaps to the nearest IEC 60063 preferred
value, and reports the ACHIEVED result plus the error so you can see
if the snap is good enough or a tighter Args:
kind: Which calculation:
- Returns:
|
| design_describe_circuitsA | Report the electrical behaviour of each recognised sub-circuit. Recognises the parametric blocks in a Most parameters are ratios / time-constants that need only the values, not a supply voltage, so this works on the plan alone. No Altium. Returns |
| design_suggest_diff_pair_tracesA | Recommend a controlled-impedance trace width for every differential pair in a plan. Detects the differential pairs (nets with role Returns |
| design_review_fileA | Offline FALLBACK review of a .SchDoc/.PrjPcb: OFF by default. This is NOT the preferred way to review a design. It parses the Altium file directly (OLE reader) with no running Altium and no license, so it only covers the netlist-free, component-level subset (missing MPN / datasheet / manufacturer, placeholder values, designator collisions, missing / unannotated designators, incomplete title block). It cannot compile a netlist or run ERC, and an offline parser can misread a file. Prefer the live-Altium tools whenever a session is available:
Because of that, this surface is disabled by default. To enable
it, set the environment variable Args:
path: a Returns the review report |
| design_solve_netlist_fileA | Reconstruct a .SchDoc's netlist geometrically: OFF by default. Offline FALLBACK, same opt-in as Prefer the live-Altium path ( Validated envelope: wire + power port + junction + net-label
connectivity (live Altium 24/24; pipeline buck 7/7). It faithfully
reports a net the schematic left floating; cross-sheet connectors are
out of scope. A single sheet only (a Enable with Returns |
| design_bom_fileA | Consolidated BOM from a .SchDoc/.PrjPcb on disk: OFF by default. Offline FALLBACK, same opt-in as Prefer the live-Altium Enable with Returns |
| design_review_planA | One-call offline pre-flight: bundle every plan-level analysis. Runs, on the plan alone (no Altium), the checks and reports the agent would otherwise call one by one, so the planner can vet a design in a single step before emit:
Returns |
| design_layout_schematicA | Compute the schematic layout for a DesignPlan, as pure data. THE ONE SCHEMATIC ENGINE. Every schematic tool now runs the same
canvas pipeline, so whenever you are asked to draw or lay out a
schematic, reach for this family and nothing else: this tool for
the geometry as data, It used to run a second, standalone engine whose placements and score described a layout nobody would ever see. That engine is no longer reachable: measured over ten held-out corpus sheets it lost the shared objective on seven and produced four pairs of OVERLAPPING BODIES where this pipeline produced none, so the shorter wire it appeared to draw was partly bought by stacking parts on top of one another. Runs OFFLINE and never reaches Altium, so it works on every
backend. That costs one thing and the result says which: symbol
geometry is synthesised from the plan's pin lists rather than
read from a library, so Args:
plan_json: A DesignPlan as a JSON string or a JSON object/dict.
sheet: Sheet name to report (default Returns:
Dict with |
| design_suggest_partitionA | Suggest how to split a design into balanced functional groups. Computes a min-cut partition (Kernighan-Lin style) of the plan's
components into Note: a HUB-centric design (one IC fanning out to many peripherals)
does not separate cleanly -- the hub is connected to everything, so
the cut stays high and per-sheet density barely drops. Partitioning
helps when the netlist has genuinely distinct functional blocks; read
Power/ground rails (nets touching more than Pure data; touches nothing. Assign the returned groups to part
Args: plan_json: A DesignPlan (dict or JSON string). n_groups: Number of groups to split into (default 2). max_fanout: Nets above this pin count are treated as rails and ignored for partitioning (default 8). Returns:
|
| design_execute_planA | Instantiate a DesignPlan in Altium. Two execution paths:
Both halt early if the plan contains any needs_creation parts. Resolve those first by either picking an existing-lib equivalent or branching into a library-authoring sub-task. Args:
plan_json: Either a DesignPlan JSON string, or the DesignPlan
as a JSON object/dict. The MCP framework auto-deserializes
JSON-object literals to dicts before the tool sees them,
so both shapes are accepted.
project_path: Absolute path to the target .PrjPcb. Created
if it does not exist.
use_canvas: Pick the execution path. Default Returns:
Result dict with ok / project_path / sheets_touched / placed
(list of placements) / failures / needs_creation / notes.
Canvas-path additions: |
| design_learn_from_layoutA | Capture your placement edits as training data. Workflow:
Each row carries: design_id, refdes, part_role, part_lib_ref, anchor_refdes, anchor_role, anchor_lib_ref, dx_mils, dy_mils, rot_delta_deg, design_size, ts. Anchor = highest-pin-count netlist neighbor on a non-power / non-ground net (or spatial-nearest fallback). Captures the relational placement preference, not just "I moved this 200 mils right". The accumulating log feeds Args:
project_path: Same project path you passed to
Returns: Dict with ok, rows_appended, refdes_moved, refdes_unchanged, log_path, notes. |
| design_plan_from_sheetA | Read a DesignPlan back off a schematic, including one you did not draw. Use this when you are asked to change a schematic that has no
The plan is reconstructed from what is actually drawn: the components give the parts, the compiled netlist gives the nets, and the power-port glyphs say which nets are rails. It is validated before it is returned. WHAT A SCHEMATIC DOES NOT RECORD, so you must supply it:
Then: edit the plan, call Args: project_path: The .PrjPcb the sheet belongs to. Its compiled netlist is what supplies the nets. sheet_document: Full path to the .SchDoc to read. Defaults to the active document. Returns:
|
| design_hints_from_sheetA | Current sheet positions, as placement_hints for a re-run. THIS IS HOW YOU EDIT A SCHEMATIC WITH THE ENGINE. Editing by hand means choosing coordinates, which is what sch_place_components refuses. Do this instead:
Positions come back as BODY CENTRES, the frame placement_hints
expects, converted from the symbol origins Altium reports. Pass
the returned Needs the Args: project_path: Absolute path to the .PrjPcb whose sheet to read. Returns:
|
| design_preview_planA | Render a DesignPlan to SVG without emitting to Altium. Same pipeline as Args:
plan_json: DesignPlan as JSON string or dict.
output_svg_path: Where to write the SVG. Default:
Returns: Dict with ok / preview_svg_path / canvas (snapshot) / counts {placements, wires, labels, power_ports, junctions} / notes / failures. |
| design_audit_schematicA | Structured visual/layout audit of the active schematic. Call AFTER
Args: project_path: Optional .PrjPcb path. None uses the focused project. cluster_radius_mils: Radius for stacked-port clustering. Default 600 mils. Returns:
SchematicAuditReport dict: |
| design_validateA | ERC + connectivity sanity report on the focused project. Runs run_erc, project.get_messages, and get_unconnected_pins, then bundles the output into a structured ValidationReport that the planner can read and respond to. Schematic-only in this slice, PCB validation is a separate later slice. Args: project_path: Optional absolute path to a .PrjPcb. If omitted, uses the focused project. Returns:
ValidationReport dict: |
| design_validate_requirementA | Validate a structured DesignRequirement before planning starts. Stage 1 of the autonomous flow (requirement capture & architecture,
reference/autonomy-roadmap.md): capture what the board must do as a
Checks beyond the schema: unresolved open questions, no outputs, no power source, inverted temperature / IO-voltage ranges, comms IO without a protocol, and supply rails or power outputs whose magnitude exceeds every stated power input (a boost / inverting stage the user must confirm). Pure Python, no Altium.
Args:
requirement: DesignRequirement as a JSON object/dict. Units are
SI with the unit in the field name ( Returns:
|
| design_load_fab_profileA | Validate a fab capability profile and echo the normalized form. Stage 8 of the autonomous flow (rules & stackup,
reference/autonomy-roadmap.md): before synthesizing design rules,
the fab's published limits are captured as a Args:
profile: FabProfile as a JSON object/dict: Returns:
|
| design_synthesize_rulesA | Synthesize PCB design rules + stackup ops from a fab profile. Stage 8 of the autonomous flow (rules & stackup,
reference/autonomy-roadmap.md): turn the validated fab profile, the
plan's net classes, and a few board-level targets into the concrete
Args:
profile: FabProfile as a dict (see Returns:
|
| design_plan_hierarchyA | Propose a multi-sheet hierarchy for a dense DesignPlan. Stage 6 of the autonomous flow (schematic emit,
reference/autonomy-roadmap.md): a plan past ~20 parts stops fitting
one readable sheet and dense single sheets are the known short-risk
regime. This tool partitions the parts by signal connectivity
(min-cut, zones kept atomic), names each child sheet from its
dominant zone role, derives the inter-sheet ports from the signal
nets the cut severs (power/ground rails are continuous through
power ports and never become sheet entries), and emits the
top-sheet op list in the exact parameter shapes of
Args:
plan_json: DesignPlan as a JSON string or dict.
max_parts_per_sheet: Split threshold (default 20). At or below
it the plan stays single-sheet ( Returns:
|
| design_apply_hierarchyA | Rewrite a DesignPlan onto the sheets a hierarchy proposes. Stage 6 of the autonomous flow (schematic emit,
reference/autonomy-roadmap.md), the second half of the hierarchy
step: take the result of Args:
plan_json: DesignPlan as a JSON string or dict.
hierarchy: The dict returned by Returns:
|
| sch_render_svgA | Render the active SchDoc to an SVG file (in-house renderer). SCOPE: this is a VISUAL artifact for when an image is genuinely
needed (layout/readability review, sharing a picture, a CI
thumbnail). It is NOT an input to a design review. NEVER judge
connectivity, part values, ratings, or pin functions from this
render -- a wire that looks joined may not share a net, and a
net can be correct while the drawing looks messy. Connectivity
and part facts come from the compiled netlist + part data
( Pulls every component, pin, wire, junction, net label, port and
power port from the active schematic via the bridge, then emits
a self-contained SVG with v1 draws components as labelled bounding-box bodies with pin stubs from the body to the electrical end. Full symbol-internal primitives (rectangles / lines / arcs inside each symbol) are deferred to v2 -- the v1 output is recognisable and ready for interactive overlay but does not yet draw the actual symbol art. Args:
output_path: Where to write the SVG. Defaults to the
transient Returns:
Dict with |
| pcb_render_svgA | Render the active PcbDoc to an SVG file (in-house renderer). SCOPE: a VISUAL artifact for when an image is genuinely needed
(placement / silkscreen / spacing review, sharing a picture).
It is NOT an input to a design review's electrical findings.
NEVER judge connectivity, net assignment, or clearance from this
render -- read those from the board data ( Pulls the board outline, every track, arc, pad, via, and text
primitive from the active PCB via the bridge, then emits a
per-layer SVG. Layers are grouped in render order (KeepOut at
bottom, then bottom copper, top copper, overlays, outline on
top, drills last) and every track / arc / pad / via group
carries v1 surface: board outline + tracks + arcs + pads (round / rect / octagonal / rounded-rect) + vias + texts on overlays. Regions (polygon fills / copper pours) and component-body silkscreen outlines are deferred to v1.1. Args:
output_path: Where to write the SVG. Defaults to the
transient Returns:
Dict with |
| design_visual_reviewA | Render the active design and return it as a viewable image plus a critique rubric -- the first step of a visual self-check loop. SCOPE: layout and placement ONLY -- schematic readability /
spread / flow, PCB part placement, silkscreen, spacing, overlaps.
This is NOT a connectivity or part-correctness review. Do NOT use
it to decide what connects to what, whether a value/rating is
right, or whether a pin is wired -- those come from the netlist +
part data ( Renderers are exports; this turns them into feedback. It draws
the active SchDoc or PcbDoc, rasterizes it to PNG (headless Edge)
so you can actually look at it with the Read tool, and returns a
document-specific Use it as a loop: call this, Args:
target: Returns:
Dict with |
| proj_export_bom_htmlA | Export the project BOM as a self-contained interactive HTML file. Standalone HTML page, no external CSS / JS / Altium runtime dependency. Open it in any browser; sortable columns, free-text filter, toggle between grouped (one row per value+footprint) and per-component layouts. A self-contained one-shot static export. Useful for emailing the BOM to a manufacturer, archiving with a board release, or sharing with a non-Altium reviewer. Args:
output_path: Where to write the HTML. Defaults to
Returns:
Dict with |
| audit_find_inconsistent_track_widthsA | Find nets where the maximum and minimum track widths differ by more than 2×. Classic bug pattern: a power rail (VCC / VDD / GND) is routed at 20 mil to handle the expected current, then later someone adds a connection using the editor's default 8 mil width and moves on. The result is a thin orphan stub welded to a wide bus -- under load that thin section becomes a thermal hotspot and eventually a fab rework. Most agents and human reviewers miss it because the bulk of the net looks fine. Algorithm: per net, collect min/max track widths on signal layers. Ratio > 2.0 → flag. Per-violation reports the actual widths and the (x, y) of the thinnest track on the net so the agent can jump straight to the questionable section. Pattern: SDK-derived. No community-script reference. Returns:
Dict with |
| audit_find_acute_anglesA | Find pairs of same-net tracks meeting at < 90° interior angle. Classic fab DFM check: at an acute corner the etchant pools and over-etches the inside of the bend -- the trace narrows or breaks during fabrication. Most fab houses reject sub-90° corners on critical-thickness traces in their automated DRC, but the rejection comes back days into the schedule; catching it on the desk is much cheaper. Algorithm (pure geometry, no rule dependency):
Capped at 100 violations to keep responses manageable on dense boards. Per-violation: net, layer, x_mils / y_mils of the corner, and the actual angle in degrees. Pattern: SDK-derived. The Altium Returns:
Dict with |
| audit_find_placeholder_valuesA | Find SCH component parameters containing obvious "I'll fix this later" placeholder strings that escaped a release. Matched values (case-insensitive, whole-string after trim):
Classic bug pattern: an EE drops a 100nF cap as a temporary placeholder while working out a regulator topology, types "TBD" in the Comment, moves on, never comes back. Six months later the board ships to fab with "TBD" on the assembly drawing. The fab calls confused, the schedule slips. Checks every parameter (Comment, Value, Manufacturer, MPN,
Description, etc.) on every component across the project.
Skips empty values -- those are caught by other audits
(e.g. Pattern: SDK-derived. No community-script reference; this is a defensive sanity check we should always run before release. Returns:
Dict with |
| audit_find_orphan_power_objectsA | Find schematic power-port markers (GND, VCC, +3V3 etc.) sitting off-wire. Symmetric cousin to ERC sometimes catches this when the wire ends up with no driver, but power rails frequently have multiple drivers (the real connection elsewhere, plus this phantom), so ERC sees a valid net and stays quiet. Spatial-iterates a 1-mil square at each Pattern: SDK-derived, mirrors the orphan-net-label check. Returns:
Dict with |
| audit_find_orphan_net_labelsA | Find schematic net labels whose location is NOT on any wire or bus. In Altium, a net label labels whichever wire passes through its (x, y). If the label sits in empty space (because the wire was moved during a layout pass, or was never placed), the compile produces a phantom net -- the label looks correct on paper but the signal it "names" connects to nothing under the label. ERC sometimes catches this (no driver / no load) but not always -- the other end of the same-named net often provides a load, so the violation never fires. Spatial-iterates a 1-mil square at each net label's location
for any Pattern: SDK-derived. No community-script reference; surfaced
by reviewing the Returns:
Dict with |
| audit_find_net_label_conflictsA | Find net labels that silently merge, short, or do nothing. Three failure modes that all look correct on a printed sheet:
Complements Returns:
Dict with |
| audit_find_visible_supplier_pnA | Find schematic components with a VISIBLE supplier-PN parameter. BOM hygiene rule: only the manufacturer's MPN should appear on the SCH PDF. Supplier part numbers (Digi-Key, Mouser, Newark, Arrow, RS, Farnell) change over time -- a Digi-Key bin gets retired, the part is re-binned under a new Digi-Key SKU, and an SCH PDF saying "Digi-Key 296-1234-1-ND" sends the next person picking the BOM five years from now on a wild goose chase. Manufacturer + MPN is stable; supplier PNs are not. Detects any component parameter whose name starts with
"supplier" (case-insensitive) AND Returns:
Dict with |
| audit_find_unlocked_component_primitivesA | Find placed components whose internal primitives are NOT locked. Unlocked primitives are a silent fab-bug class -- a stray click + drag in the PCB editor moves a single pad off-center within the footprint without any warning. The gerbers look fine, just slightly off, and the part doesn't solder properly because the pad no longer aligns with the device's lead. Library footprints ship with PrimitiveLock=True by default; components show up unlocked when someone clicked Component Properties and toggled the flag off (sometimes deliberately to nudge silkscreen, more often accidentally). Returns:
Dict with |
| audit_find_mirrored_pcb_textA | Find free-floating PCB text (eTextObject) that's mirrored on the wrong overlay. Rule: top-overlay text must read normally; bottom-overlay text must be mirrored. When the assembled board is flipped to access the bottom side, the bottom text reads correctly. A normally-oriented bottom-side text reads backwards on the physical board -- the kind of thing that gets caught only at the fab-review stage by the customer's QA, then triggers a respin. Note: this checks free-floating text (revision strings, layer labels, copyright notices) -- NOT component designators or comments, which Altium auto-flips with the component. Returns:
Dict with |
| audit_find_mixed_designator_rotationA | Find PCB silkscreens where designators face BOTH 0 and 180 (or both 90 and 270) -- the assembly-readability check. Assembly inspectors and pick-and-place operators read silkscreen from a fixed angle. If half the designators on the top overlay read normally and the other half are upside-down (0 vs 180), QC has to physically rotate the board between parts -- slow, error-prone, and the kind of thing fab houses charge extra to deal with. Orthogonal mixes (0 + 90) are fine because the inspector turns their head, not the board. The check runs per overlay layer (top, bottom) independently -- a top side with mixed 0/180 doesn't excuse a clean bottom. Returns:
Dict with |
| audit_find_non_embedded_imagesA | Find schematic images that are NOT embedded -- they hold only a path reference to the original file. Non-embedded images render fine on the designer's own machine but show a red X / placeholder box on every other machine that opens the schematic, because the path doesn't resolve. Common offenders are company-logo title-blocks dragged in from a network share and never re-saved with EmbedImage=True. The manufacturer / customer sees broken images on the SCH PDFs. Returns:
Dict with |
| audit_find_single_pin_netsA | Find nets that have EXACTLY ONE pin AND at least one net-label / port / power-object on them. A single-pin net is normal for unused / no-connect pins. A single-pin net with a named label is a broken connection: the designer asserted "this signal goes somewhere" by naming it but the other end never made it onto the schematic. Common causes are a typo in a net-label that doesn't match its peer, a sheet-entry vs port-name mismatch on a hierarchical block, or an off-page connector that was deleted while routing was being re-arranged. The flat hierarchy is queried ( Returns:
Dict with |
| audit_find_mpn_inconsistenciesA | Find groups of ICs with the same (lib_ref, comment) but DIFFERENT Manufacturer Part Numbers. Two presumably-identical parts pointing at different MPNs is almost always a bug: either a typo / accidental override during a sub-circuit clone, or means the design genuinely wants two sources but lost the alternates table somewhere. The agent reviewing the BOM should see this before purchase. Pattern: ports the dashboard's analyzeMpnConsistency JS heuristic to an authoritative Pascal-side audit. Returns:
Dict with |
| audit_find_missing_datasheetsA | Find ICs (designator U*) with no fetchable datasheet URL in any of their parameters. Checks the standard Altium slots:
At least one of those needs to carry an Pattern: ports the dashboard's pickDatasheetLinks heuristic to an authoritative Pascal-side audit. Returns:
Dict with |
| audit_find_pin_net_name_mismatchesA | Find IC pins whose NAME looks like a power / ground pin but whose connected NET is not actually a power / ground rail. Examples flagged:
Pattern: ports the dashboard's JS-side analyzePinNetMismatch as an authoritative MCP audit. Returns:
Dict with |
| audit_find_missing_decouplingA | Find ICs whose power pins lack a nearby decoupling cap. For every IC, identify its power pins (by net name or by pin name pattern). For each power pin, check if any capacitor (designator C*) shares the same net. Buckets:
ICs with full coverage are not surfaced (no problem to fix). ICs with NO recognised power pins are skipped (we can't distinguish "no power needed" from "couldn't detect"). Catches the single most-skipped pre-release review check: a missing local bypass doesn't fail ERC, doesn't fail DRC, but bites at first power-on with brown-outs / random resets. Pattern: ports the dashboard's JS-side analyzeDecoupling. Returns:
Dict with |
| audit_find_unconnected_ic_pinsA | Find IC pins with an empty / unset net (excluding pins intentionally named NC / DNC / RSVD / RESERVED). Walks the project BOM (cheap: uses the already-cached
Same heuristic the Components tab's "unconnected IC pins" chip runs in JS, but now exposed as a first-class MCP tool so the agent can drill in from one call and the result is consistent between the dashboard and the lint sweep. Returns:
Dict with:
- |
| audit_component_param_visibilityA | Check that every placed component shows the parameters its class requires for a legible schematic and a procurable BOM. Per-class rules:
The check looks at component parameter slots and the on-canvas Comment field; either is acceptable. Hidden values (IsHidden=True) do NOT satisfy the rule because they're invisible during review. Operates on the compiled / flattened doc tree (same as the BOM) so multichannel and hierarchical designs are covered. Returns:
Dict with:
- |
| audit_power_port_orientationA | Check that schematic power-symbol orientations follow the standard convention so reviewers' eyes can scan the sheet quickly. Rules:
Stylistic but high signal: a flipped ground symbol or a sideways rail is invariably an editing accident, and one violation can hide a real wiring issue under it because the eye keeps wanting to fix the orientation first. Returns:
Dict with:
- |
| audit_tented_via_ratioA | Count tented vs untented via SURFACES on the active board and report the tented ratio. Untented vias expose the via barrel through solder mask; in humid or salt-spray environments that risks acid traps and copper corrosion. For consumer boards spec is usually "all vias tented top + bottom"; for prototyping boards a lower ratio is fine. Counts top and bottom surfaces separately (a via reaching only the top layer contributes one surface, a through-via two). Buried / blind via surfaces that don't reach an outer layer are ignored. Returns:
Dict with:
- |
| audit_find_floating_portsA | Find schematic ports that aren't actually connected to anything. On each schematic sheet a port is "floating" if its net does not appear on any component pin OR any sheet-symbol entry on the same sheet. A floating port is usually an editing leftover (renamed a net but forgot to retag the port) or a never-completed hookup -- ERC can miss these when the port carries a valid net-label tag that just doesn't connect to anything physically. Walks the compiled / flattened doc tree so multichannel / hierarchical designs are covered. Returns:
Dict with:
- |
| audit_find_bad_connectionsA | Find PCB tracks / arcs with endpoints that are close to another same-net primitive but don't actually touch. Walks every track / arc on a signal layer. For each endpoint, looks
for ANOTHER same-net primitive (track / arc / pad / via) within
Visual review misses these because at 100% zoom the gap is invisible; DRC sometimes catches them under a "Clearance" or "Modified Polygon" rule but not reliably. Skipped: teardrops (intentionally offset), primitives inside components (they ride the pad), primitives without a net, full circle arcs (no anchor endpoint). Args: tolerance_mils: Coord tolerance in mils. 0 = exact match required (rare, since router can place tracks on sub-mil grid). Defaults to 1 mil; bump to 5 or 10 to surface gross misalignments only. Returns:
Dict with:
- |
| audit_find_signal_vias_without_returnA | Find signal vias that have no nearby ground / power via for return-current flow. For every via NOT on a ground/power net (heuristic: net name
starts with GND / V / + / - or contains "GND"), look for at least
one ground/power via within Tradeoff: this is a SIMPLIFIED proximity heuristic, not a stackup- aware analyser. The full check (reference-layer tagging, stripline vs microstrip rules, paired-reference handling) is a much larger GUI-driven analysis. For first-pass review, proximity flags the obvious cases. Args: radius_mils: How close a return via must be. Default 50 mils (~1.3mm) -- typical "good practice" is within 1-2 mm of the signal via. Returns:
Dict with:
- |
| audit_find_pads_near_board_edgeA | Find PCB pads / vias closer than Copper too close to the routed edge gets scuffed / scored / torn during v-cut + mouse-bite break. IPC-2221 and typical fab houses want at least 20-50mil clearance for critical components, more for connectors. Worth tightening to 50+ for boards going to depaneling rather than rounded-corner manufacture. The gap is measured from the outline's own segments, lines and arcs, to the pad's copper: a via or round pad by its radius, a rectangle by its nearest corner or edge midpoint, at whatever rotation. Round and other curved outlines are covered. Args: clearance_mils: Minimum gap to flag as a violation (default 25). Try 50 if your fab depanels by v-cut. Returns:
Dict with:
- |
| audit_find_components_outside_board_outlineA | Find PCB components whose origin sits outside the board outline. Editing accident catch: the user grabbed a component and moved it off the PCB by mistake. Usually invisible during normal review because the component is off-canvas; DRC doesn't catch it (DRC is between primitives, not "is this object on the board"). Uses Pattern: brett's SelectCMPInOutSideBOL.pas. Returns:
Dict with:
- |
| audit_find_off_grid_componentsA | Find schematic components placed off the snap grid. Schematic best practice: components sit on a 100-mil (or whatever the project standard is) grid so pins land predictably on wire endpoints. Off-grid placement is the classic "I edited around it and never resnapped" trap: the symbol LOOKS wired but the pin doesn't actually touch the wire, ERC silently passes (no visible net) and the connection is missing on the netlist. Args: grid_mils: Grid size to check against (default 100). Use 50 if your sheets are set to a half-step grid. Returns:
Dict with:
- |
| audit_find_removed_pad_shapesA | Find pads / vias whose copper annular ring has been removed on layers where it's still needed. Altium's "Tools → Remove Unused Pad Shapes" optimization deletes per-layer pad copper where a primitive isn't electrically used on that layer. Applied too aggressively, it leaves a via that drills through an inner layer with NO annular ring there: any later trace edit on that inner layer that tries to land on the via will silently fail to connect at fab. Detection:
Pattern: brett's PadShapeRemoved.pas (read-only; we surface coordinates rather than highlight on canvas). Returns:
Dict with:
- |
| audit_find_designator_collisionsA | Find schematic components that share a designator across sheets. Annotation should make every designator unique across the project, but paste-from-another-sheet operations and post-annotate edits can leave duplicates that the agent / reviewer want to surface before they hit ERC. Walks source schematic sheets (not compiled docs: compiled flattening would auto-disambiguate multichannel instances with channel suffixes, hiding the real source-level collision). Returns:
Dict with:
- |
| audit_find_via_antennasA | Find vias connected on only one layer (resonating stubs). At RF / high data rates the unused side of a one-layer-connected via acts as an open-ended transmission-line stub: it resonates at frequencies whose quarter-wavelength matches the stub length, reflecting signal back into the trace and degrading rise time + EMC compliance. Common after iterative editing where a layer-change via gets stranded when the destination trace was later rerouted on a different layer. Counts a via "connected" on a layer when:
Returns a JSON list (rather than selecting and highlighting). Cost: O(vias × layers × spatial-prims-near-via). Typical boards finish in 1-3 seconds; very dense boards may take longer. Returns:
Dict with:
- |
| audit_find_unmatched_portsA | Find schematic nets with port-direction mismatches across sheets. Catches the two cases that matter most:
Walks compiled docs so multichannel designs are covered. Ports are grouped by their flattened net name, so net-label renames keep ports correctly clustered. Returns:
Dict with:
- |
| audit_variant_not_fittedA | List components marked Not Fitted in the project's CURRENT variant. Manufacturing context: a Not-Fitted component is on the BOM as a placeholder but should NOT receive paste on the stencil, otherwise the SMT line deposits paste on empty pads and bridging forms on rework. Many houses also want a "DNP" silkscreen marker on the artwork. This tool returns the list of components the agent should consider for those treatments. This is the identify half. Returns:
Dict with:
- |
| audit_find_invalid_regionsA | Find PCB polygon regions whose area is zero or unset. These are leftover from cancelled polygon-pour operations or corrupted file imports. They don't render visibly but can throw DRC violations under "Modified Polygon" rules and bloat board size. Read-only: this tool only surfaces them. Auto-delete belongs in a separate user-confirmed mutating flow because misclassification could remove a real (legitimately small) region. Returns:
Dict with:
- |
| pcb_autorouteA | Route the focused board with the in-house layout engine, as a job. Reads the board exactly ( This is the in-house engine: no Altium autorouter, no external program. Inner layers a pour covers are used as planes and not routed on; a redundant one is given back to routing when the board cannot be completed without it. With the stage switches on, the routing runs in planned stages, each one's copper fixed for the next: differential pairs (coupled at their gap, skew evened with bumps), a dog-bone via for every pad a plane or pour joins (never a via in a passive's pad; an exposed pad gets a via array), access lanes kept straight out of fine-pitch IC pins, buses laid as nested lanes, then everything else negotiated, high-current nets first, then rails, then the rest. Every bend is 45 degrees or less, and no via goes into a passive's pad. Over 160 finished boards these defaults routed 98.93% mean against 98.85% for the router before the stages (two boards fewer at 100%, all DRC-clean, about 29% more time); plane fanout is off by default because it cost completion. With all four switches off this is the router before the stages, exactly. Args: expect_file: full path of the board to route. The read refuses on the first reply if the focused board is another one. nets: route only these nets; all other copper stays as it is. None routes every net with two or more pads. use_planes: treat inner layers a single pour covers as planes (default True). diff_pairs: route the board's differential pairs (its own definitions, else read from _P/_N, +/-, DP/DM net names) as coupled pairs first (default True). plane_fanout: give every surface pad of a plane or pour net its dog-bone via before the signals (default False). pin_lanes: keep the first 0.8 mm straight out of each IC pin at 0.65 mm pitch or finer for that pin's own net (default True). bus_lanes: lay three or more nets between the same two parts as one group of nested lanes (default True). Returns:
|
| pcb_autoroute_applyA | Write a finished Refuses unless the focused board is Args:
job_id: a Returns:
|
| pcb_autoplaceA | Place the focused board's parts with the in-house placer, as a job. Reads the board exactly ( Two strategies. "blocks" plans the board by sub-circuit first: each IC with its decoupling, pull-ups and filters in columns round it, connectors with the parts on their lines, passives in rows, repeated channels as identical tiles in a grid, the blocks placed in signal-flow order from the connectors; its result also lists the blocks (name, rectangle in mils, members) and every part the legaliser had to move, with the moves over 80 mil flagged as floorplan problems. "analytic" places by wirelength alone (quadratic placement, spreading, legalising, refinement). Parts keep their side. Locked parts, and parts whose designator
starts like a connector, mounting hole, fiducial, test point, switch
or battery, stay where they are unless named in This is the in-house engine: no Altium auto-placer, no external program. Args:
expect_file: full path of the board to place. The read refuses on
the first reply if the focused board is another one.
parts: designators to move; every other part stays. None moves
every part that is not locked or mechanical (see above).
compact: spread the parts over only as much room as they need,
round where their connections pull them, instead of over the
whole board. For a small circuit on a large board; over the
benchmark boards it routes slightly worse, so it is off by
default. Analytic strategy only.
strategy: "blocks" or "analytic"; None takes the placer's
default, "blocks". A board where the floorplan has to push
more than a quarter of its parts out of place is placed by
"analytic" instead, and the result says so under
Returns:
|
| pcb_autoplace_applyA | Move the parts of a finished Refuses unless the focused board is Args:
job_id: a Returns:
|
| route_planA | Route the board offline (grid A*) and return placeable ops. Pure Python -- no Altium round-trip unless Live sequence: fetch geometry -> this tool ->
Args:
geometry: Returns:
|
| route_plan_repairsA | Turn a DRC violation payload into an ordered repair plan. Pure Python, stateless. Classifies the Executor contract: apply the actions in order
( Args:
violations: Returns:
|
| review_designA | EDA-agnostic design review of the open board. Runs the same netlist-level review regardless of the active EDA
(Altium or KiCad): board stats and net classes, annotation hygiene
(unannotated, duplicate references, missing values), and connectivity
(single-pin nets, shorted pins/components, unconnected parts and pads,
missing decoupling). Geometric DRC (clearances, courtyards) is separate and backend-specific. |
| get_board_infoB | Object counts and net-class summary for the open board, from the
active backend (or the one named by |
| list_componentsB | Every component on the open board (reference, value, footprint,
kind), from the active backend (or the one named by |
| run_drcA | Run geometric design-rule check (DRC) on the open board. Dispatches to the active backend: Altium runs its native DRC; KiCad
runs |
| run_ercA | Run the schematic Electrical Rules Check (ERC) on the open design. Dispatches to the active backend: Altium runs its native ERC; KiCad runs
|
| list_netsB | Every net on the open board with pin count and class (power / ground
/ signal), from the active backend (or the one named by |
| tool_catalogA | Discover tools by category / maturity / interaction without loading every schema. The surface has 350+ tools; loading them all strains a client's context. This meta-tool returns a filtered, classified index so a client can find the right tool first, then rely on its full schema. Filters (all optional, AND-combined):
category: core, application, project, library, generic,
schematic, pcb, audit, design, simulation, routing, meta,
parts (and kicad on the KiCad backend; the EasyEDA tools
file under the same subject headings as Altium's, so
"pcb" means the same thing on either). "core" holds the
EDA-agnostic main flow (review_design, get_board_info,
list_components, list_nets, run_drc, run_erc) and is the
usual starting point. Call with NO filter to get the live
Returns |
| tool_invokeA | Invoke any registered tool by name: the companion to
A client with a limited context can expose only the core tools plus
this pair: discover a tool with GET THE ARGUMENT NAMES FIRST. Under the minimal toolset no schema
is loaded up front, so call
Returns the tool's own result (JSON-decoded), or |
| tool_guideA | How to do something correctly, and what is genuinely impossible. USE THIS BEFORE CONCLUDING A CAPABILITY IS MISSING. The recorded
failures are not "could not find the tool name", which
Answers three distinct things, kept apart on purpose: the tool and its prerequisites, the tool you were probably reaching for and why it acts on another document, and the short list of things that are proven impossible with the reason. An empty result means this guide has nothing on the subject. It
is not evidence that the server cannot do it: fall back to
Search here for help when a tool seems missing, when you are not
sure which tool to use, when an operation seems not supported,
or when a call failed because the wrong document was open.
( Args: task: What you are trying to do, in your own words, e.g. "delete silkscreen from a footprint". Matched on keywords, so a rough phrase is fine. document_kind: Narrow to one of library, board, schematic, project, any. Optional. backend: altium, kicad or easyeda. Optional; omit to see every backend's answer. Returns:
Dict with |
| part_searchA | Search EVERY enabled part provider and merge the results. No provider is a default and none is preferred: all are queried equally, hits carry the provider that found them, and the merged order is alphabetical by provider then part. That ordering is NOT relevance, so do not read the first hit as the best one. Each provider reports its own status. A provider that cannot answer says why (endpoint withdrawn, software missing) instead of returning nothing, because "unavailable" and "no such part" are different answers and only one means stop looking. Call with an empty query to list the providers and what they are, including who operates them. TWO KINDS OF SOURCE, merged but never conflated. A The two answer different questions rather than ranking against each other: a catalogue tells you WHICH part to use and hands you the datasheet every check here measures against, and a library tells you whether you can draw it. NOTE on maturity="offline": in this catalog that means "needs no Altium", which is true here. It does NOT mean "needs nothing": the remote providers want the internet. With no network the search still succeeds on whatever local providers are enabled (kicad_local reads libraries already on disk) and reports the remote ones as unavailable, so a degraded answer is still a useful one. DATASHEET DISCIPLINE: a hit is a lead, not a verified part. The
Args: query: substring matched against part name, manufacturer and keywords. Empty lists the providers instead. limit_per_provider: cap per source, so one large registry cannot crowd out the others. Returns:
|
| part_fetchA | Fetch one part's detail, by the Pass the The source is still explicit, never inferred. Nothing here picks
a provider for you: a bare id with no Set Downloaded files are checked against the KiCad installed on this
machine: a registry may publish a NEWER s-expression format than
the local KiCad can open (observed live, format 20260206 against
KiCad 10.0.1's 20251024, where the symbol parser refuses the file
outright). Any such file comes back with a Returns the provider's own detail plus a normalised summary
(mpn, manufacturer, datasheet, provenance, license) where the
provider supplies one, and |
| design_live_viewA | Open the live layout view and return its URL. Makes sure the local dashboard is running (it usually is, started with the MCP server) and points at its Layout tab, which draws the board as the in-house placer and router change it: parts, pads, tracks per layer, vias, pours, blocks and planned lanes, with new and moved items glowing for 30 s and removed copper fading out. Next to it is the decision log, newest first, and a status line (routed n / N nets, k partly). Give the URL to the user so they can watch while you work. Reads files only; no bridge call. Args: open_browser: also open the URL in the default browser. Returns:
|
| design_live_noteA | Log a decision to the live view, before acting on it. The Layout tab lists decisions newest first next to the board, so the user sees what is about to happen and why, and can stop it. Call this BEFORE the step it describes, one decision per call, in a sentence or two: what you will do and the reason (the datasheet figure, the rule, the measurement). Args:
section: what the decision is about, a short label such as
Returns:
The logged entry |
| design_live_snapshotA | Publish a board to the live view as its next version. The placement and routing jobs publish on their own, and their
apply tools republish what they wrote. Use this for any other
board state: the board as it is in the EDA now ( Only Args: note: what this snapshot shows; also logged as a decision. board_json_path: a LayoutBoard JSON file. expect_file: full path of the focused board, to read it from Altium as it is now. The read refuses if another board is focused. (Neither: republish the board the last engine job, apply or snapshot in this server published.) Returns:
|
| datasheet_fetchA | Download a datasheet PDF into the workspace and return its path. Read the returned Refused, with nothing stored: a URL that is not http or https; a
file over 50 MB; a server that does not answer within 60 s; and a
reply that is not a PDF (no Args: url: the datasheet's http or https URL, ideally the manufacturer's own. part_number: recorded in the sidecar, for the citation. Returns:
|
| footprint_check_packageA | Check a package description for numbers that cannot be right. Run this on every package transcribed from a datasheet, before drawing a footprint from it. Offline. Sanity checks (each finding names the dimensions, their values and
citations, and why the combination is impossible or unusual):
limits in order; lead width below the pitch; each row of pins fits
the body it comes out of; lead span larger than the body for
leaded parts; the foot shorter than the lead's reach and two
terminals fitting the span; the exposed pad inside the body and
clear of the terminals; ball diameter below the pitch; values 25.4
times off their neighbours (mils typed as mm); pin counts the
family can have; the vendor land pattern consistent with itself.
Cross-check, when the package carries the datasheet's recommended
land pattern as Args: package: the PackageSpec as an object or JSON text, the same schema lib_create_footprint_from_package takes. Returns:
|
| footprint_render_packageA | Draw the land pattern a package gives, to compare with its datasheet. Offline. Renders the footprint the engine would build (lands with their numbers, paste windows, silkscreen with the pin 1 dot, assembly outline, courtyard, origin and a 1 mm scale bar) and draws the package's terminals over the lands as dashed green outlines, so a land that misses its terminal shows. A caption gives the pattern's pitch, span and land sizes. Read the returned image next to the datasheet's package drawing and recommended land pattern. Args:
package: the PackageSpec as an object or JSON text.
density: L, N or M (least, nominal, most).
path: where to write the SVG; default
Returns:
|
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| autonomous_design | Drive a full spec-to-board design run with the harness. |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 480 tools
The 480-tool set contains many near-overlapping tools: app_run_menu vs app_click_menu vs app_run_ui_command; app_list_open_dialogs vs app_read_window vs app_ui_snapshot; proj_get_nets vs proj_get_connectivity vs proj_get_component_info; and many audit_find_* and pcb_get_* variants. Descriptions often explain distinctions, but the sheer breadth makes misselection likely for an agent.
There are recognizable prefix families (app_, proj_, lib_, pcb_, sch_, design_, audit_, sim_), but many tools use bare names (list_components, run_drc, run_erc, get_board_info, review_design, route_plan, tool_invoke). Snake_case is mostly preserved, but verb styles and prefixing conventions vary widely across the surface.
480 tools is far beyond a well-scoped set; even a large EDA automation suite does not justify this count for an agent-facing MCP server. tool_catalog and tool_invoke mitigate discovery, but the raw surface remains extreme and impractical to load or reason about reliably.
The surface covers project and document lifecycle, schematic and PCB CRUD, library authoring, simulation, routing, auditing, BOM/export, UI driving, and meta-tooling. Despite redundancy, there is no obvious core gap for the stated Altium/EDA automation domain.