KiCad
Schematic capture, PCB layout, and electronics design. Supports KiCad native, Gerber, and BOM export formats.
Documentation
Get a computer-use agent controlling a managed desktop application environment in under five minutes.
Using another language? Read the REST API docsInstall the Python SDK from PyPI. Requires Python 3.9 or later. Use version 0.2.0 or later for all methods on this page, including persistent execution and structured observations.
python -m pip install --upgrade 'isle-sdk>=0.2.0'Continue with GitHub or email at tryisle.com, then create an API key in the dashboard.
export ISLE_API_KEY=isle_...from isle import Client
isle = Client()
sandbox = isle.sandboxes.create(
"kicad",
name="Power supply board",
idempotency_key="power-supply-board-v1",
)
sandbox.wait_until_ready()
print(f"Sandbox ready: {sandbox.id}")
print(f"Stream: {sandbox.stream_url}")Use familiar computer-use primitives: screenshots, mouse, keyboard, and file transfer. Individual uploads and downloads are limited to 4 MiB.
# Take a screenshot
image = sandbox.screen.screenshot()
# Mouse control
sandbox.mouse.click(500, 300)
sandbox.mouse.move(200, 400)
sandbox.mouse.scroll(0, -500)
# Keyboard control
sandbox.keyboard.type("8 mm")
sandbox.keyboard.keypress(["CTRL", "S"])
# File transfer
sandbox.files.upload("input.step")
sandbox.files.download("/home/user/work/result.step")Retained recordings are finalized by the signed environment monitor and streamed directly to durable storage. A recording is capped at 512 MiB, six hours, or low disk space; the API reports whether it was truncated and why. Stop requests are durable and can be retried safely while shutdown is still in progress.
# Stop archives the sandbox. Files persist, billing pauses.
sandbox.stop()
sandbox.wait_until_stopped()
# Resume restores the sandbox on fresh hardware
sandbox.resume() # blocks until runningUse sandbox.destroy() to permanently delete a stopped environment and its retained data.
Persistent Python
Give your agent a persistent Python session on the application's desktop. Combine short PyAutoGUI action sequences, screenshots, installed command-line tools, and project files in/home/user/work. Variables and imports persist between cells in the default namespace.
Create a new KiCad or FreeCAD environment and use Isle SDK 0.2.0 or later. Existing environments keep their original image; check capabilities before submitting code. These APIs work with any model or agent framework that can call HTTP tools.
python -m pip install --upgrade 'isle-sdk>=0.2.0'# Isle SDK 0.2.0+ and a new environment.
from isle import Client
client = Client() # ISLE_API_KEY stays in this client process
sandbox = client.sandboxes.get("YOUR_SANDBOX_ID")
capabilities = sandbox.capabilities()
assert capabilities["execution"]["available"]
generation = capabilities["generation"]
result = sandbox.execution.run(
"counter = 41\nlog(counter)\ndisplay(pyautogui.screenshot())",
expected_generation=generation,
timeout_seconds=30,
)
print(result["status"], result["stdout"])
assert result["status"] == "succeeded"
result = sandbox.execution.run(
"counter += 1\nlog(counter)",
expected_generation=generation,
)
print(result["stdout"]) # 42
observation = sandbox.screen.observe()The namespace starts with pyautogui, time,log(), and display(). Keep PyAutoGUI's fail-safe enabled. Inspect the returned status and send emitted PNGs to the model as image inputs. Observations include the generation, capture time, screen dimensions, and scale factor;active_document is currently null.
Use execution.submit(), get(),wait(), and cancel() when you need to manage a cell separately. Preserve its UUID and generation before submission. An ExecutionSubmissionUnknown carries those identifiers: query the original execution before deciding on new work. A client wait timeout leaves the remote cell running.
One desktop operation runs at a time. Wait after an explicitdesktop_busy rejection. Cancellation and server timeouts stop the worker, verify held-key and mouse-button cleanup, and reset Python state. Completed file or application edits remain. Refresh capabilities and inspect the desktop after a generation change. Background Python processes pause between cells.
Cells allow up to 64 KiB of UTF-8 source and 120 seconds. Output is bounded; check capabilities["limits"]and output_truncated. Images fromdisplay() remain in runtime records; download them before eviction or restart. Retained observations use the existing screenshot storage.
New IPC-enabled KiCad images include the official kipyPython client. Check for kicad_ipc in capability features, open the intended PCB in the editor, then run this inside an execution cell. It works with any model or agent.
from kipy import KiCad
kicad = KiCad(timeout_ms=2000)
kicad.ping()
board = kicad.get_board()
print(board.name)
print(len(board.get_footprints()))IPC reads and edits the live PCB. Confirm the document before changing it, inspect the result, and call board.save()before CLI validation or checkpoints. Reconnect after a generation change; a timed-out edit may already have happened. Existing environments keep their original image. Schematic automation and headless IPC are outside this KiCad 10 integration.
Use FreeCAD's installed freecadcmd interpreter for its FreeCAD and Part modules. Run it from an execution cell, then open the saved document in the GUI to inspect its feature tree and shape. The persistent worker itself uses standard Python.
import subprocess
result = subprocess.run(
["/usr/local/bin/freecadcmd", "-c",
"import FreeCAD as App; print(App.Version())"],
capture_output=True, text=True, timeout=30, check=True,
)
print(result.stdout)Save the native project at /home/user/work/project.FCStdfor checkpoints. Download STEP and other exports through the file API. Save GUI edits before checking files, and avoid rewriting a document from another process while it is open.
Model integration example
The repository's examples/astra/run.py connects the OpenAI Responses API with Astra to the same execution and observation tools available to any model. Use the SDK and environment described above, then install the example's client dependencies:
python -m pip install -r examples/astra/requirements.txt
python examples/astra/run.py YOUR_SANDBOX_IDKeep OPENAI_API_KEY in your client process, outside Python cells and desktop files. The example sends returned PNGs as image inputs, preserves tool call IDs, and reconciles uncertain executions. It uses serial calls; asynchronous model tools and steering are not implemented.
examples/astra/validate.py checks saved KiCad copies with CLI ERC, DRC, and schematic parity. The live PCB API is documented above; an Isle MCP connector is not included. Bounded KiCad and FreeCAD tasks have been validated through Codex, including saved-file checks and visual review. The optional Responses adapter has offline coverage; its own live API run remains unverified.
Complete workflow
A complete script that creates a KiCad sandbox, uploads a file, performs some operations, and downloads the result.
from isle import Client
isle = Client() # uses ISLE_API_KEY env var
# Create environment
sandbox = isle.sandboxes.create("kicad", name="Power supply board")
sandbox.wait_until_ready()
# Upload input
sandbox.files.upload("schematic.kicad_sch")
# Your agent takes over here
# Use sandbox.screen.screenshot() to see the screen
# Use sandbox.mouse and sandbox.keyboard to interact
# Download result
sandbox.files.download("/home/user/work/board.kicad_pcb", "board.kicad_pcb")
# Stop when done, then permanently delete the environment.
sandbox.stop()
sandbox.wait_until_stopped()
sandbox.destroy()Applications
Schematic capture, PCB layout, and electronics design. Supports KiCad native, Gerber, and BOM export formats.
3D modeling, parametric design, and engineering tasks. Supports STEP, IGES, STL, OBJ, and native FreeCAD formats.
Reliability
Create a checkpoint explicitly before an important operation. When you need to return to it, call sandbox.recover() to restore the latest safe checkpoint and restart the application.
# Manual checkpoint
sandbox.checkpoint()
# Check monitor health
status = sandbox.monitor_status()
print(status) # {"status": "running", "checkpoints": 5, ...}
# Lifecycle failures are also available on every sandbox response
sandbox.refresh()
if sandbox.last_error:
print(sandbox.last_error, sandbox.last_error_at)
# Full error history, newest first
errors = sandbox.errors()
# List checkpoints
checkpoints = sandbox.checkpoints()
# Manually trigger recovery
sandbox.recover() # restores last safe checkpoint + restarts appEach environment is scoped to its intended application. Terminal, browser, package manager, and system-settings windows are blocked. On execution-enabled images, Python and installed CLI tools run inside the restricted worker with the shared workspace and no external network access.
SDK methods
| Method | Description |
|---|---|
sandboxes.create(env, name=...) | Create a named environment |
sandboxes.list() | List all sandboxes |
sandboxes.get(id) | Get a sandbox by ID |
sandbox.wait_until_ready() | Wait for sandbox to start |
sandbox.capabilities() | Discover runtime support, limits, and generation |
sandbox.screen.observe() | Capture a structured desktop observation |
sandbox.execution.run(code, ...) | Submit one cell and wait for its result |
sandbox.execution.submit(code, ...) | Submit one cell with an execution ID and generation |
sandbox.execution.get(id, generation=...) | Read an existing execution result |
sandbox.execution.wait(id, generation=...) | Wait for an existing execution to finish |
sandbox.execution.cancel(id, ...) | Cancel a cell and inspect namespace reset |
sandbox.screen.screenshot() | Capture screenshot (PNG bytes) |
sandbox.mouse.click(x, y) | Click at coordinates |
sandbox.mouse.move(x, y) | Move cursor |
sandbox.mouse.scroll(x, y) | Scroll |
sandbox.keyboard.type(text) | Type text |
sandbox.keyboard.keypress(["CTRL", "S"]) | Press key combo |
sandbox.files.upload(path) | Upload a file |
sandbox.files.download(path) | Download a file |
sandbox.checkpoint() | Create a safe checkpoint of the artifact |
sandbox.recover() | Restore the last checkpoint and restart the app |
sandbox.checkpoints() | List all checkpoints |
sandbox.download_checkpoint(id) | Get a checkpoint download URL |
sandbox.events() | List command trace events |
sandbox.errors() | List timestamped lifecycle errors |
sandbox.recording_url() | Get the environment recording URL |
sandbox.export_json() | Export actions and recording/screenshot links |
sandbox.recording_info() | Get URL plus recording truncation metadata |
sandbox.monitor_status() | Get application health status |
sandbox.last_error | Latest lifecycle error returned by the API |
sandbox.last_error_at | Timestamp of the latest lifecycle error |
sandbox.stop() | Stop and archive a sandbox |
sandbox.wait_until_stopped() | Wait for a stop operation to finish |
sandbox.resume() | Resume a stopped sandbox |
sandbox.destroy() | Permanently delete a stopped environment |