Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

atech

Firmware for Atech boards from one small file, built so a coding agent can drive it.

An Atech board is an ESP32-S3 with numbered ports; modules slide into the ports. You (or Claude Code, Cursor, any agent that can run a shell) describe the build in project.yaml. The SDK picks the pins, assembles the drivers, generates the firmware, compiles it, flashes it, and then lets you talk to the board from your computer. No cloud account. Nothing in this package phones home.

You:   "make the light go red when I press the button"
Agent: atech list-modules → atech info button → writes project.yaml
       atech validate → atech build → atech upload → atech check

Install

pip install atech

Python 3.10+. PlatformIO comes with it. The first atech build downloads the ESP32 compiler, about 2.4 GB on disk, once. After that, builds work offline and take seconds. A module that needs a library (the light grid, for one) fetches it the first time a project uses it.

Sixty seconds

atech new blink --board 14port     # project.yaml + AGENTS.md / CLAUDE.md for your agent
cd blink

Edit project.yaml:

name: blink
board: 14port
modules:
  - {id: button,   instance: btn, port: 1}
  - {id: neopixel, instance: led, port: 2}
code:
  loop: |
    if (btn.wasPressed()) { led.setAll(255, 0, 0); led.show(); }
atech describe .     # what is placed, each module's API, its events and actions
atech validate .
atech build .
atech upload .       # board on USB, data cable
atech check          # which modules answered after boot

Then, from the computer:

atech monitor                                   # [button] btn = 1
atech send led_fill r=0 g=0 b=255               # ok: the board carried out led_fill

For coding agents

atech guide            # the guide: workflow, rules, what will bite you
atech guide protocol   # the wire format: events, actions, acknowledgements

atech new writes the guide into the project as AGENTS.md and CLAUDE.md, so an agent started in that folder reads it without being told.

Commands

atech guide [protocol]                 the docs above
atech list-boards [--json]             boards, their module ports and UART ports
atech list-modules [--category X] [--json]
atech info <module> [--json]           description, cautions, C++ API, events, actions
atech new <name> --board <id>
atech describe [dir]                   a project's modules, API, events and actions
atech validate [dir]
atech build    [dir]
atech upload   [dir] [--port X]
atech check                            reboot the board; which modules answered, and why not
atech monitor  [--key K,K] [--type T,T] [--json]
atech send <key> [value]               exit 0 only if the board confirmed it (value: r=0 g=255, a number, or JSON)
atech ports                            USB ports that look like a board
atech free-port                        release a port another process holds

Every command prints error: … on stderr and exits non-zero when it fails.

Python

import atech

atech.list_boards(); atech.list_modules(category="sensor")
atech.get_module("button").usage            # the C++ API of a module

p = (
    atech.Project(board="14port", name="blink")
        .add("button",   port=1, instance="btn")
        .add("neopixel", port=2, instance="led")
        .set_loop('if (btn.wasPressed()) { led.setAll(255, 0, 0); led.show(); }')
)
print(p.describe())                         # modules, API, events, actions, cautions
p.validate()                                # -> list of placement issues
p.build()                                   # -> BuildResult
p.upload()                                  # -> UploadResult
atech.Project.load("blink")                 # a folder or a project.yaml

with atech.Board.connect() as board:        # NoBoardFoundError if no board is on USB
    board.call("led_fill", {"r": 0, "g": 0, "b": 255})   # raises unless the board confirms
    for ev in board.events(keys=["btn"]):
        print(ev.key, ev.value)

board.call() waits for the board's acknowledgement, and board.query(action, reply=event_key) returns the value the board answers with. board.send() only writes to the port and tells you nothing. One program holds a board's port at a time: stop atech monitor before atech send or atech upload.

Robot arm: check the power supply and the arm first

The Robot Arm module passes the board's high-voltage rail (labelled 12 V) straight to the servos. That rail is fed by a power module (the power jack module, or the USB-C PD power module) and carries whatever that module is given. Nothing regulates it, and the standard USB-C module does not feed it.

  • SO-101 arms come in a 12 V and a 5 V version.
  • The supply must match the arm: a 12 V supply for the 12 V arm, a 5 V supply for the 5 V arm.
  • A 12 V supply on a 5 V arm damages the servos.
  • Never plug more than 12 V into the jack.
  • Check the voltage printed on the supply, and which arm you have, before you connect anything.
  • Both versions have been run this way: power jack module and Robot Arm module, nothing outside the Atech stack.

atech validate, atech build and atech upload print this as a CAUTION whenever a project contains robot_arm.

Bringing your own module

my_project/
├── project.yaml          # add:  modules_path: ./my_modules
└── my_modules/
    └── lidar_v2/
        ├── module.yaml   # id, templates, usage, events, actions, lib_deps
        ├── lidar_v2.h
        └── lidar_v2.cpp

Same shape as the bundled modules, which sit in the installed package under atech/catalog/data/modules/. A module with the same id as a bundled one replaces it. Declare only events the loop template really prints, and give every action a handler:.

How it is put together

atech.Project          the spec: board, modules on ports, your code
atech.placement        checks ports: reserved, overlap, adjacency, interface
atech.catalog          bundled and user modules
atech.codegen          templates → main.cpp + platformio.ini (no LLM in this path)
atech.build / upload   PlatformIO
atech.runtime.Board    serial client for the flashed board

Status

Alpha. atech list-boards and atech list-modules show what this version contains. Not in the SDK: WiFi, over-the-air updates.

License

MIT.

Metadata

Release files for atech 1.0.0a11

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

Source distribution (sdist)

Source distribution for atech 1.0.0a11
File Size Uploaded Provenance Actions
atech-1.0.0a11.tar.gz 109.9 kB Without provenance Details for atech-1.0.0a11.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for atech 1.0.0a11
File Interpreter ABI Platform Actions
atech-1.0.0a11-py3-none-any.whl Python 3 none any Details for atech-1.0.0a11-py3-none-any.whl

Total release size: 256.7 kB

Release files / atech-1.0.0a11.tar.gz

Download URL atech-1.0.0a11.tar.gz
Size 109.9 kB
Tags Source
SHA-256 checksum
How to use checksums
41f7e44cddca0880a9c3abf171e009b4cb21aeaa3ae996de885f4c236598559c
BLAKE2b-256 checksum
How to use checksums
4d6b55d38603601a709ec5f0e90d3fea3c2eec31324e5e605ab55147c0a706b1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"CachyOS Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / atech-1.0.0a11-py3-none-any.whl

Download URL atech-1.0.0a11-py3-none-any.whl
Size 146.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
47aaa3fe8fd32f39a77ce024651a23edb31dc1abc7756164cda65cd7b58aa8b4
BLAKE2b-256 checksum
How to use checksums
2453802c0724d3b5bedbeb3bd8d35ecb64dd26cd46db0b10df73c6fe3bac4059
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"CachyOS Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for atech 1.0.0a11

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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