Skip to main content

AutoAssembler Python SDK

AutoAssembler is C-Infinity's foundational AI for assembly process planning: read a CAD assembly, analyze its geometry, motion and production logic, and turn that into manufacturing process plans, diff analysis, DFA analysis, work instructions and more. This package is the official Python client for the AutoAssembler API. From a script or a notebook you can:

  • Upload a CAD assembly (STEP, PVZ) and get a processed Assembly back.
  • Plan it: create a process plan, assign parts to stations, let the planner work out the assembly sequence, then validate that every station is physically buildable.
  • Diff two revisions of an assembly and adapt an existing plan to the new one.

Status: 0.x. The surface may still change between minor releases; see Versioning. The v4 API is stable, except the operations under client.alpha.

Documentation

  • The Quickstart below, then the Examples for each task in more depth.
  • Every public class and method has a docstring: help(client.planning), help(mpp.plan), or your editor's hover.
  • autoassembler --help for the command line.

Installation

pip install autoassembler        # or: uv add autoassembler
pip install 'autoassembler[cli]' # also the `autoassembler` command (see Command line)

Requires Python 3.12+.

Authentication

Create an API key in the AutoAssembler app under Settings → API keys → Create API key, then either pass it explicitly, set AA_TOKEN, or log in interactively once:

from autoassembler import AutoAssembler

client = AutoAssembler(token="aa_...")     # explicit (CI, scripts)
client = AutoAssembler()                   # reads AA_TOKEN, or the token stored by login()
import autoassembler
_ = autoassembler.login()   # confirm in your browser; stores the token for 30 days

login() stores tokens in ~/.config/autoassembler/credentials.json; logout() forgets them. login() also returns the token: assign its result as above to avoid displaying it in a notebook or interactive shell. Do not commit credentials or include them in reports. logout() removes the local copy; it does not revoke the token on the server. Pass base_url= to both login() and AutoAssembler() for anything but https://app.autoassembler.com, including your own deployment.

Quickstart

Use your own CAD files in place of the example filenames below; no CAD data is bundled. These calls upload the files to the configured service and create resources in your account.

from autoassembler import AutoAssembler

client = AutoAssembler()

# Upload two revisions of a design. Processing overlaps on the server; wait for both.
v1, v2 = (op.result() for op in (client.assemblies.upload("gearbox_v1.step"),
                                  client.assemblies.upload("gearbox_v2.step")))

# Plan v1 from scratch: one station with every part, plan it, check it is buildable.
mpp = client.planning.create_mpp(v1, name="Gearbox v1")   # a manufacturing process plan
station = mpp.add_station("Final assembly")
outcome = mpp.plan(station).result()           # complete | partial | failed
verdict = mpp.validate(station).result()       # feasible | infeasible
print(outcome[station].status, verdict[station].status, mpp.viewer_url)

# What changed in v2, and v1's plan carried over to it.
diff = client.assemblies.diff(v1, v2).result()
mpp_v2 = client.planning.adapt(mpp, v2, diff=diff).result()

Examples

Each example below assumes client = AutoAssembler() and a valid token (see Authentication). Long-running calls take a timeout in seconds; OperationTimeout means the work is still running on the server, not that it failed.

Upload several CAD files

upload() returns as soon as the file is transferred, with processing under way on the server. Start every upload before waiting on any, and the processing overlaps:

from autoassembler import AutoAssembler, OperationFailed, OperationTimeout

client = AutoAssembler()
paths = ["gearbox_v1.step", "gearbox_v2.step", "housing.pvz"]   # .step, .stp or .pvz

ops = [client.assemblies.upload(path) for path in paths]
for path, op in zip(paths, ops):
    try:
        assembly = op.result(timeout=1800)
    except (OperationFailed, OperationTimeout) as error:   # e.g. the file is not an assembly
        print(f"{path}: {error}")
        continue
    print(f"{path} → {assembly.id}  {assembly.viewer_url}")

Work with existing assemblies and plans

Everything you created earlier is reachable by id:

assembly = client.assemblies.get("asm-1")
print(assembly.name, assembly.status)          # processing | ready | failed

for mpp in assembly.plans():                   # every process plan of the assembly
    print(mpp.id, mpp.name)
mpp = client.planning.get_mpp(assembly, "mpp-1")

structure = assembly.structure()               # the processed eBOM
connections = assembly.connections()           # part-to-part connections (liaison graph)

Compare two revisions

Both assemblies must be ready. The report's summary holds the counts and details the parts behind them:

report = client.assemblies.diff("asm-1", "asm-2").result(timeout=1800)   # handles or ids

summary = report.summary
if summary.total_parts:
    print(f"parts: {summary.total_parts.reference} → {summary.total_parts.target}")
if summary.geometric_diffs:
    print(f"only in v1: {summary.geometric_diffs.reference}")
    print(f"only in v2: {summary.geometric_diffs.target}")
for swap in report.details.swaps or []:
    print(f"swap: {swap.reference_part} → {swap.target_part} ({swap.confidence})")
for moved in report.details.moved_pose_pairs or []:
    print(f"moved: {moved.reference_part}")

Plan, validate and score a process plan

A new plan knows the assembly's parts and has no stations. add_station takes every unassigned part by default, or the subset you pass as parts=:

mpp = client.planning.create_mpp(assembly, name="Gearbox — two stations")
print(len(mpp.unassigned_parts), "parts to assign")

subassembly = mpp.add_station("Shaft subassembly", parts=mpp.unassigned_parts[:5])
final = mpp.add_station("Final assembly")               # everything left

outcome = mpp.plan(*mpp.stations).result(timeout=1800)  # one or more stations
for station in mpp.stations:
    status = outcome[station]
    print(station.name, status.status)                  # complete | partial | failed
    for message in status.messages:                     # what a partial plan could not place
        print("  -", message)

verdict = mpp.validate().result(timeout=1800)          # no arguments: every station
for station in mpp.stations:
    if station in verdict:                              # stations with no planned steps are skipped
        print(station.name, verdict[station].status, verdict[station].messages)

if verdict.ok:                                          # every station feasible
    dfa = mpp.evaluate_dfa().result(timeout=1800)       # design-for-assembly scores
    for station_id, report in dfa.items():
        print(mpp.station(station_id).name, report.total_score, report.average_score)

print(mpp.viewer_url)                                   # open the plan in the app

outcome.ok is true when every station planned complete. evaluate_dfa needs stations that are planned and feasible.

Carry a plan over to a new revision

Rather than planning a revision from scratch, adapt the previous revision's plan: stations and steps carry over, adjusted for what changed.

v1, v2 = client.assemblies.get("asm-1"), client.assemblies.get("asm-2")
plan_v1 = client.planning.get_mpp(v1, "mpp-1")

diff = client.assemblies.diff(v1, v2).result(timeout=1800)
try:
    plan_v2 = client.planning.adapt(plan_v1, v2, diff=diff, name="Gearbox v2").result(timeout=1800)
except OperationFailed as error:
    raise SystemExit(f"adaptation failed: {error.message}")

for station in plan_v2.stations:
    print(station.name, station.status)

Resume an operation from another process

Every Operation has a name. Store it, and pick the operation up later, from any process, without starting the work again:

op = mpp.plan(station)
print(op.name)                                   # e.g. "operations/…"; save it somewhere

# later, elsewhere
from autoassembler import AutoAssembler
op = AutoAssembler().operations.handle(saved_name)
if op.done():
    print(op.result())

A resumed operation returns the raw API response rather than the typed result (PlanOutcome, Assembly, …); refresh the plan or look the assembly up to read it.

Clean up

mpp.delete()          # a process plan
assembly.delete()     # an assembly (only your own uploads)

Command line

The cli extra installs the autoassembler command, for shell scripts and agents. Each command is a thin layer over the same calls (uvx --from 'autoassembler[cli]' autoassembler runs it without installing):

autoassembler login                                  # once; or set AA_TOKEN
autoassembler status                                 # versions, server, and who you are logged in as
autoassembler assemblies upload gearbox_v1.step gearbox_v2.step    # one `ID  STATUS  FILE` row each
mpp=$(autoassembler plans create asm-1 --name "Gearbox v1")        # creating commands print the id
autoassembler plans add-station asm-1 "$mpp" "Final assembly"
autoassembler plans plan asm-1 "$mpp"                # every station; or name some, by id or name
autoassembler plans validate asm-1 "$mpp" --json     # one JSON document on stdout
autoassembler assemblies diff asm-1 asm-2
autoassembler plans adapt asm-1 "$mpp" asm-2

autoassembler --help (or -h), and the same on any command, lists the rest. Conventions:

  • Results go to stdout and progress to stderr. --json prints the result as one JSON document, with this SDK's field names.
  • Exit codes: 0 success; 1 the request ran and the result is a failure (an API error, a failed operation, a station that failed to plan, an infeasible station); 2 usage; 3 not authenticated; 4 still running when --timeout ran out (it keeps running on the server).
  • Long-running commands wait (up to --timeout, 1800 s by default). --no-wait prints the operation's name instead, for autoassembler operations wait NAME later.
  • The server is https://app.autoassembler.com unless --url or AA_URL says otherwise.

How the SDK is organized

  • Concepts. Assembly (a CAD file the service knows) and ProcessPlan (a manufacturing process plan for one assembly, made of Stations).

  • Actions. upload, diff, plan, validate, evaluate_dfa, adapt. An action that creates a resource lives on a namespace (client.assemblies.upload, client.planning.adapt); an action that acts on an existing resource lives on that resource's handle (mpp.plan(station)).

  • Waiting. Anything that outlives its HTTP request returns an Operation[T]. op.result(timeout=None) polls with backoff and returns T, or raises OperationFailed / OperationTimeout; op.done() checks without blocking. Start several, then collect:

    ops = [client.assemblies.upload(p) for p in cad_files]
    assemblies = [op.result() for op in ops]
    

Outcomes use the document's own words: a station's planning status is pending, complete, partial (a usable partial plan) or failed; its validation verdict is feasible or infeasible, with the issues behind it; an assembly is processing, ready or failed.

The full API: client.api

The curated layer above is built on a client generated from the v4 OpenAPI spec, available as client.api (client.api.assemblies.get_status(...), client.api.planning.get_mpp(...)). Use it when the vocabulary above does not cover what you need, and tell us what was missing. Every endpoint method carries its own docstring (help(client.api.planning.get_mpp)), and the whole tree is browsable from help(client.api).

Errors

Failure Raised as
The server answered with an error status ApiError (status_code, body, headers), or a typed subclass: BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError
The response did not match the expected schema ParsingError (not an ApiError)
No response at all (DNS, connection, timeout) httpx.HTTPError subclasses
A long-running operation failed or was cancelled OperationFailed (code, message, operation)
A long-running operation did not finish in time OperationTimeout (a TimeoutError)

Async

AsyncAutoAssembler currently exposes the generated client (client.api) and client.operations; the curated assemblies / planning namespaces arrive on the async client in a later release under the same names, with asyncio.gather as the natural way to run work in parallel.

Advanced

  • Timeouts. 60 s per request by default: AutoAssembler(timeout=20.0) or request_options={"timeout": 5} per call.
  • Retries. Requests that fail with 408, 409, 429 or 5xx are retried twice with backoff; request_options={"max_retries": 0} turns it off per call.
  • Your own httpx client, for proxies or transports: AutoAssembler(httpx_client=httpx.Client(proxy="http://...")).
  • Raw responses. client.api.<namespace>.with_raw_response.<method>() returns headers and status alongside the parsed data.
  • Context managers. with AutoAssembler() as client: closes the connection pool.

Compatibility

API AutoAssembler v4 (autoassembler.API_VERSION == "v4"). The client is generated from the v4 OpenAPI spec.
Servers https://app.autoassembler.com by default; any AutoAssembler deployment that serves the v4 API via base_url=.

Versioning

The package follows semantic versioning, independently of the API version. While 0.x, a minor release may change the surface and a patch release only fixes; from 1.0, breaking changes need a major release and removals are deprecated for one minor release first. Pin a minor version (autoassembler~=0.4.0) if you need a stable surface while on 0.x.

Alpha

Operations the API offers before they are stable sit under client.alpha (also client.api.alpha): today client.alpha.jobs and client.alpha.planning.apply_ops. They are outside these guarantees: any release may change or remove them. An operation that becomes stable moves out of alpha, to its namespace's usual place.

Support

Bug reports, feature requests and questions: write to info@c-infinity.ai. For a bug, include the SDK version (python -c "import autoassembler; print(autoassembler.__version__)"), your Python version, and, for a failed operation, its name. Do not include API keys or tokens.

License

MIT © C-Infinity. The license text ships with the package.

Metadata

Release files for autoassembler 0.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for autoassembler 0.4.1
File Size Uploaded
autoassembler-0.4.1.tar.gz 148.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for autoassembler 0.4.1
File Interpreter ABI Platform
autoassembler-0.4.1-py3-none-any.whl Python 3 none any Details

Total release size: 352.9 kB

Release files / autoassembler-0.4.1.tar.gz

Download URL autoassembler-0.4.1.tar.gz
Size 148.1 kB
Tags Source
SHA-256 checksum
How to use checksums
ef24d35c23ff8b6752543491ce410dae9c8d3ba2d7aa62cdbe1873b914929868
BLAKE2b-256 checksum
How to use checksums
e0061182e0f1c012d32d5ac9548915f7b4af7104b2d74eb61571d0a283ce3bd4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / autoassembler-0.4.1-py3-none-any.whl

Download URL autoassembler-0.4.1-py3-none-any.whl
Size 204.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
706d822478a5125a40c18de84aa5acb5cf78070386448f528392481ae00437e1
BLAKE2b-256 checksum
How to use checksums
afb539711b9cd57fb7c68ffafd42048600da08754332ce693db60aa2061d9242
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.1 This release

2 release files

0.3.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page