Metadata-Version: 2.4
Name: machinome
Version: 0.8.0
Summary: Source code for machines — a Python framework for mechanical design and simulation
Author-email: Luis Fagundes <lhfagundes@gmail.com>
License-Expression: GPL-2.0-or-later OR CERN-OHL-S-2.0+
Project-URL: Homepage, https://github.com/machinome/machinome
Keywords: machinome
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.11
Description-Content-Type: text/x-rst
License-File: LICENSE
License-File: LICENSES/CERN-OHL-S-2.0.txt
License-File: LICENSES/GPL-2.0-or-later.txt
Requires-Dist: watchdog
Requires-Dist: trimesh==4.4.*
Requires-Dist: httpx==0.27.*
Requires-Dist: fastapi==0.111.*
Requires-Dist: termcolor==2.4.*
Requires-Dist: asgiref==3.8.*
Requires-Dist: uvicorn==0.30.*
Requires-Dist: numpy==2.2.*
Requires-Dist: rtree
Requires-Dist: scipy
Requires-Dist: shapely==2.1.*
Provides-Extra: dev
Requires-Dist: machinome[all]; extra == "dev"
Requires-Dist: bump2version; extra == "dev"
Requires-Dist: flake8>=7; extra == "dev"
Requires-Dist: tox>=4; extra == "dev"
Requires-Dist: coverage>=7; extra == "dev"
Requires-Dist: Sphinx>=7; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pillow>=10; extra == "dev"
Requires-Dist: black>=25.1; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: pyyaml; extra == "dev"
Requires-Dist: pytest-watch; extra == "dev"
Requires-Dist: ipython; extra == "dev"
Requires-Dist: ipdb; extra == "dev"
Provides-Extra: docs
Requires-Dist: sphinx; extra == "docs"
Requires-Dist: sphinx_rtd_theme; extra == "docs"
Provides-Extra: viewer
Requires-Dist: machinome-viewer; extra == "viewer"
Provides-Extra: web-snapshot
Requires-Dist: machinome-viewer[snapshot]; extra == "web-snapshot"
Provides-Extra: mechanics
Requires-Dist: machinome-mechanics; extra == "mechanics"
Provides-Extra: brep
Requires-Dist: cadquery-ocp<7.9,>=7.8.1; extra == "brep"
Provides-Extra: mesh
Requires-Dist: manifold3d; extra == "mesh"
Provides-Extra: cadquery
Requires-Dist: cadquery==2.7.*; extra == "cadquery"
Requires-Dist: machinome[brep]; extra == "cadquery"
Provides-Extra: build123d
Requires-Dist: build123d==0.10.*; extra == "build123d"
Requires-Dist: ocp-gordon<0.3,>=0.2.2; extra == "build123d"
Requires-Dist: machinome[brep]; extra == "build123d"
Provides-Extra: step
Requires-Dist: cadquery==2.7.*; extra == "step"
Requires-Dist: machinome[brep]; extra == "step"
Provides-Extra: molejo
Requires-Dist: molejo[brep]==0.2.*; extra == "molejo"
Requires-Dist: machinome[brep]; extra == "molejo"
Provides-Extra: openscad
Requires-Dist: solidpython2==2.1.*; extra == "openscad"
Provides-Extra: solid2
Requires-Dist: machinome[openscad]; extra == "solid2"
Provides-Extra: jscad
Provides-Extra: stl
Provides-Extra: all
Requires-Dist: machinome[brep,build123d,cadquery,jscad,mesh,molejo,openscad,solid2,step,stl]; extra == "all"
Provides-Extra: studio
Requires-Dist: machinome-studio; extra == "studio"
Dynamic: license-file

=========
Machinome
=========

**Source code for machines**

.. image:: https://github.com/machinome/machinome/actions/workflows/python-app.yml/badge.svg?branch=main
   :target: https://github.com/machinome/machinome/actions/workflows/python-app.yml
   :alt: Build status

.. image:: https://img.shields.io/pypi/v/machinome.svg
   :target: https://pypi.org/project/machinome/
   :alt: PyPI version

.. image:: https://readthedocs.org/projects/machinome/badge/?version=latest
   :target: https://machinome.readthedocs.io/en/latest/
   :alt: Documentation status

Machinome is a Python framework for giving a machine source code.
Describe its parts, the dimensions they share, how they fit together,
what moves, and the relationships that make the whole machine work.
Its geometry, operating behaviour and tests belong to the same project.

A gear ratio connects the gears you see to the movement you test.
An input moves the parts it drives. A spring follows the mechanism
that compresses it. A calculator remembers its digits when the crank
returns to rest. These relationships are explicit in the machine's
source, where they can be inspected, changed and tested.

Supply parts using CadQuery, build123d, OpenSCAD/SolidPython or JSCAD;
reuse STEP and STL designs; derive sheet parts from cutting profiles;
and describe flexible springs, belts and cables with
`molejo <https://molejo.readthedocs.io>`_.
Machinome binds the pieces together through assemblies, shared parameters,
joints, laws, inputs and stored state. Incremental builds give feedback
as you edit. The optional browser viewer lets people operate and explore
the machine, including from an exported static web page.

Machinome is developed empirically from mechanical projects, with
AI-assisted design and implementation; `AI-USE.md <AI-USE.md>`_ records
which agents, since when, and how the history marks their work. The
`Machinome Foundry <https://github.com/machinome-foundry>`_ organisation
holds simulations of open-source machines built with it, each beside the
design it simulates; the framework, viewer and mechanics packages live
under `machinome <https://github.com/machinome>`_. Simulation and geometric tests
provide evidence about those models; they do not establish that every
design has been manufactured or physically validated.

Version 0.8: a lean core
========================

Machinome 0.8 installs only the CAD kernels a project's parts use: each
kernel and node family is an extra. Every name is imported from the one
module that defines it, and a test compares parts on the B-rep engine or the
mesh engine, named for what each consumes. Machinome is licensed
**GPL-2.0-or-later or CERN-OHL-S-2.0-or-later**, at the recipient's choice.

Install it with the browser viewer and start a project:

.. code-block:: bash

   pip install "machinome[viewer,cadquery]"
   machinome new myproject
   cd myproject
   machinome develop

With that install the starter part is a B-rep CadQuery part; where
SolidPython is installed too (``machinome[solid2]``) it is a SolidPython part,
which needs the OpenSCAD executable, and the manual's first page replaces it
with a B-rep CadQuery part. Each CAD kernel is an extra named for the
module that needs it (``cadquery``, ``build123d``, ``step``, ``molejo``,
``openscad``, ``solid2``, the two engines' ``brep`` and ``mesh``, or
``all``). The
`upgrading guide <https://machinome.readthedocs.io/en/latest/project/upgrading.html>`_
lists every breaking change from 0.7 to 0.8 and what to change.

Version 0.7 and the new name
============================

Machinome 0.7 is the direct continuation of **solid-node 0.6.0**.
The framework and GitHub organisation were renamed to avoid confusion
with Tim Berners-Lee's Solid project: `solid-node` sounded like a Solid
node, and `LibreSolid` like a libre edition of Solid. Machinome has no
affiliation with that project. The same guide maps imports, commands,
configuration and viewer integration from 0.6; there is no ``solid_node``
import shim or ``solid`` command alias.

Learn it one machine at a time
==============================

The `tutorial <https://machinome.readthedocs.io/en/latest/tutorial/01-part.html>`_
builds a hand-cranked tally counter from a part to a machine with memory:
an input moving a body through a joint, shared dimensions, relations and
laws, buttons, fit tests proved red first, a stepped scenario, a running
machine with a ratchet, and retained digits written at events.

Real machines built with Machinome, posed, running and clocked, are shown
live on `machinome.org <https://machinome.org/>`_, each beside its design
source and licence.

* `User manual <https://machinome.readthedocs.io/en/latest/>`_
* `0.8 release notes <https://machinome.readthedocs.io/en/latest/releases/release-0.8.html>`_
* `0.7 release notes <https://machinome.readthedocs.io/en/latest/releases/release-0.7.html>`_
* `Source repository <https://github.com/machinome/machinome>`_

Machinome is licensed **GPL-2.0-or-later or CERN-OHL-S-2.0-or-later**, at
the recipient's choice. The optional
`Machinome Viewer <https://github.com/machinome/machinome-viewer>`_
is a separate package, licensed **AGPL-3.0-or-later**, installed through
``viewer``. Ordinary ``machinome develop`` requires it. Without it, the
framework builds, tests, exports with ``--no-widget``, watches with
``develop --no-web``, and takes fixed-pose OpenSCAD snapshots with the
``openscad`` extra.

The ``mechanics`` extra installs the independent
``machinome-mechanics`` helpers. The ``studio`` extra is reserved for
Machinome Studio, an experimental, unpublished harness; it cannot yet
resolve from a package index.

Working on Machinome itself
============================

This section is for contributors — humans and coding agents — who modify the
framework in this repository. For *using* machinome in your own mechanical
project, see the documentation above.

Development environment
-----------------------

Requirements: Python >= 3.11. Node.js is not needed: the browser viewer and
its widget live in the separate `machinome-viewer
<https://github.com/machinome/machinome-viewer>`_ repository, and the tests
that need a viewer skip unless that package is installed. `OpenSCAD
<https://openscad.org/>`_ is conditional: put it on the PATH when working on
SolidPython2/Solid2 or raw OpenSCAD nodes, or the default OpenSCAD snapshot
renderer. All-B-rep projects — CadQuery,
build123d, or the two mixed — build, test, and export without it; use
``machinome snapshot --renderer web`` for snapshots on a machine without OpenSCAD.

`manifold3d <https://pypi.org/project/manifold3d/>`_, the mesh engine's
kernel, is the ``mesh`` extra (``pip install "machinome[mesh]"``, included
in ``all``) and is conditional in the same sense: it decides mesh geometry,
so it is needed whenever an assertion compares a part that has no B-rep
geometry, by ``machinome test --mesh``, and by
``assertAssemblySupported``, whose statics phase reads contact patches off
meshed intersections for every body. An all-B-rep project's other
geometric assertions are decided by the B-rep engine and run without it — useful on a
platform with no compiled wheel, such as WebAssembly. A path that needs it
and cannot import it says so by name, naming the extra.

Clone the repository (the tutorial's machine under ``docs/tutorial/`` is
built and tested by the suite; the real machines the manual points to are
on machinome.org, not in this repository):

.. code-block:: bash

    $ git clone https://github.com/machinome/machinome.git
    $ cd machinome

Create a virtualenv and install the package in editable mode with the dev
dependencies:

.. code-block:: bash

    $ python -m venv .venv
    $ source .venv/bin/activate
    $ pip install -e ".[dev]"

The ``machinome`` CLI entrypoint (``machinome/cli.py``) is now on the PATH of
the virtualenv.

Running tests
-------------

The test suite is pytest, run from the repository root:

.. code-block:: bash

    $ make test          # equivalent to: pytest
    $ pytest tests/test_builder_lifecycle.py   # a single file
    $ make lint          # flake8 + black --check
    $ make test-all      # tox across supported Python versions

Notes:

* Rendering tests invoke the real ``openscad`` binary. On a headless machine,
  snapshot-related tests may need ``xvfb-run -a pytest ...``.
* Browser-snapshot tests are mandatory for changes to that renderer. Install
  a matching viewer with its ``snapshot`` extra (from source while it is
  unpublished), then install Chromium and run the real capture explicitly:

  .. code-block:: bash

      $ playwright install chromium
      $ MACHINOME_WEB_SNAPSHOT_E2E=1 pytest tests/test_browser_renderer.py::BrowserSnapshotEndToEndTest

  The ordinary suite leaves this environment variable unset and skips the
  capture, even when the viewer is installed. With the opt-in set, a missing
  viewer or browser is a setup failure. The dedicated CI browser-snapshot job
  installs both dependencies, sets the opt-in, and runs this same test.
* ``tests/meta_project/`` together with ``tests/test_meta.py`` is the
  end-to-end meta-project harness: it runs small real machinome projects —
  both deliberately green and deliberately red fixtures — to prove the
  loading, rendering, and ``machinome test`` subprocess paths. Use it when a
  change touches behavior that direct unit tests cannot establish; see
  `docs/contributor-briefing.md <docs/contributor-briefing.md>`_ for when and
  why.
* The browser viewer's own tests live in the ``machinome-viewer``
  repository. ``tools/generate_parity_fixture.py`` produces, from this
  framework's render results, the parity fixture that repository commits
  beside its expression evaluator.

Where things live
-----------------

* ``machinome/node/`` — the node tree (base, assembly, fusion, the leaf
  bases, one module per node type, operations)
* ``machinome/engine/`` — the B-rep and mesh engines and their seams
* ``machinome/manager/`` and ``machinome/cli.py`` — the ``machinome`` command:
  develop loop, test, snapshot, new, export
* ``machinome/core/`` — build pipeline, loader, caching
* ``machinome/simulation/`` — drivers, instructions, the stepped ``Sim``
  loop, and ``ScenarioTest``
* ``machinome/test.py`` — mesh-oriented test cases and assertions
* ``machinome/viewers/`` — the OpenSCAD snapshot renderer, the lookup
  of the installed ``machinome-viewer`` package, and the staging half of the
  web snapshot renderer (the photograph itself is the viewer's)
* ``tests/`` — Python test suite
* ``docs/`` — Sphinx documentation, architecture synthesis, ADRs
* ``openspec/`` — OpenSpec change proposals and baseline specs

Development discipline
======================

This repository is developed agentically and follows a strict
spec-first discipline. **Every behavioral change starts as an OpenSpec
change proposal and is ratified before implementation.** Drive-by edits,
unrecorded redesigns, and "fix it first, document it later" are not how
this project moves — this applies equally to human contributors and to
coding agents operating autonomously.

OpenSpec changes
----------------

Behavioral contracts live in ``openspec/specs/``. Changes are proposed,
reviewed, implemented, and archived through the OpenSpec workflow
(`OpenSpec <https://openspec.ai>`_, CLI v1.x; the repo's
``openspec/config.yaml`` carries project context and rules):

1. **Propose** — create a change under ``openspec/changes/<name>/`` with
   ``proposal.md`` (why, what changes, capabilities, impact), ``design.md``
   (how), and ``tasks.md`` (implementation steps). The change describes
   *deltas* against the current specs.
2. **Review** — the proposal is inspected and refined before any code is
   written. Specs describe observable behavior only; no aspirational
   requirements.
3. **Apply** — implement the ratified proposal, task by task, TDD-style:
   red evidence first (a failing test that pins the contract), then the
   smallest change that satisfies it.
4. **Archive** — when the change lands, its spec deltas are merged into
   ``openspec/specs/`` and the change moves to ``openspec/changes/archive/``.

The proposal and completed record belong in this repository's
``openspec/`` directory. See `CONTRIBUTING.rst <CONTRIBUTING.rst>`_
for the contribution workflow.

Architecture Decision Records
-----------------------------

*Why* the system is the way it is lives in ``docs/adrs/`` (see
`docs/adrs/README.md <docs/adrs/README.md>`_ for the index and the full
discipline):

* One decision per ADR, numbered sequentially, filed under the subsystem it
  affects (NODE, BUILD, IPC, MATH, TEST-FRAMEWORK, VIEWER-WEB, EXPORT).
* Statuses flow ``Proposed`` → ``Accepted``; later ADRs may mark earlier ones
  ``Superseded``. Superseded ADRs stay in the log — they are the history that
  makes current decisions legible.
* When an OpenSpec change carries an architectural shift, its ADR is written
  alongside the change and the architecture synthesis
  (`docs/architecture.md <docs/architecture.md>`_) is updated as part of
  landing it.

Read order for orientation: **architecture synthesis first**
(``docs/architecture.md``), **then the specs** for exact observable behavior
(``openspec/specs/``), **then an ADR** when you need to know why
(``docs/adrs/``). The contributor briefing
(`docs/contributor-briefing.md <docs/contributor-briefing.md>`_) adds
verification guidance: how to choose between direct pytest coverage and the
meta-project harness, and the red-first evidence principle.

Contributing
============

Bug reports and pull requests are welcome at
https://github.com/machinome/machinome — see
`CONTRIBUTING.rst <CONTRIBUTING.rst>`_ and the development discipline above.
