Metadata-Version: 2.4
Name: axiometa-cli
Version: 2.0.2
Summary: Axiometa hardware truths and upload methods, for your editor and your AI.
Author-email: Axiometa <dr.dumcius@gmail.com>
Project-URL: Homepage, https://axiometa.io
Project-URL: Studio, https://studio.axiometa.io
Keywords: hardware,ai,mcp,esp32,nrf52840,arduino,iot,cli,maker,embedded
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Hardware
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: pyserial>=3.5

# axiometa-cli

**Hardware truths and upload methods, for a repo that is not ours.**

You are deep in an existing project and adding Axiometa hardware to it. Your editor is your editor,
your AI is your AI, your files are yours. This provides the two things neither of them can derive:
what the board actually is, and how to get firmware onto it.

It creates nothing in your repo — no manifest, no config file, no convention about where a sketch
lives. Every command is stateless.

```bash
pip install axiometa-cli
axiometa login <key>                                 # from Studio -> account menu -> Headless
axiometa provision                                   # once per machine
axiometa board genesis-one                           # pins, buses, fqbn, silicon gotchas
axiometa part  genesis-one AX22-0005                 # one part's pins, library, init, rules
axiometa upload ./firmware -b genesis-one --parts AX22-0005
```

## Hardware truths

An Axiometa board is a custom board package. Its pins, its `esp32:esp32:axiometa_*` target and its
parts match nothing in a stock core, so none of it is inferable — and a wrong pin map compiles
cleanly and fails silently in hardware.

| | |
|---|---|
| `boards` | what exists, and what language each speaks |
| `board <id>` | ports and pin naming, shared vs unique buses, which pins read analog, fqbn, build options, silicon gotchas |
| `parts <id>` | the catalog: every module, display, onboard radio, host part |
| `part <id> <part>` | one part's real pins, i2c address, library name+version, locked init, coding rules |

Add `--json` to any of them. That is the form an agent wants.

## Upload methods

| | |
|---|---|
| `provision` | install the private toolchain (~7 GB, 15-20 min, once per machine) |
| `devices` | what is plugged in |
| `compile <dir> -b <board>` | build with the right target, profile and libraries |
| `upload <dir> -b <board>` | build and put it on the board |

`--parts AX22-0005,AX22-0031` names what the build uses, which decides the libraries. You name them
because there is no manifest to read them from, and guessing from `#include`s is how a build ends up
with the wrong library. `--option PartitionScheme=app_max_no_ota` sets a build option.

## MCP

```bash
axiometa mcp
```

The same tools over stdio, for clients that speak MCP. Six: `list_boards`, `get_board`, `list_parts`,
`get_part`, `compile`, `upload`. File editing and shell are the client's own job, so they are not here.

It holds no prompt and does no reasoning. Your AI writes the code.

## It cannot collide with your Arduino setup

Axiometa boards are a custom board package laid into a **pinned** ESP32 core (3.3.6 — 3.3.7/3.3.8
carry a NimBLE regression that boot-loops Matter sketches on ESP32-S3). Installing that into a shared
arduino-cli would rewrite `boards.txt`, replace your core version, and add libraries to your
sketchbook.

So we never touch yours. Everything lives in one prefix:

```
~/.axiometa/toolchain/
  bin/arduino-cli          our own pinned binary — never the one on your PATH
  arduino-cli.yaml         our own config, passed as --config-file on every invocation
  data/                    our cores + our patched boards.txt
  user/libraries/          our libraries
  venv/                    our mpremote / adafruit-nrfutil
```

Your `arduino-cli`, your core version, your `arduino-cli.yaml`, your sketchbook and your Python
environment are never read and never written. Uninstall is `rm -rf ~/.axiometa`.
`AXIOMETA_HOME` moves the prefix.

## Where the knowledge comes from

The CLI ships no board data. It fetches `GET /api/knowledge/boards` from its own service (`server/`,
deployed separately) and caches it under `~/.cache/axiometa/`, re-fetching only when the content hash
changes. A board or part added upstream reaches every installed CLI with no release.

That fetch needs a **key**. Studio mints one per signed-in account (account menu -> Axiometa
Headless); `axiometa login <key>` stores it, or set `AXIOMETA_KEY`.

The token is HMAC-signed and carries a public `key_id`:

```
axm_<base64url(user_id:key_id:issued_at)>.<hmac-sha256>
```

Signature first, database second. The HMAC proves authenticity with no lookup, so a forgery is
rejected before anything touches the database. The `key_id` is then what makes a single key
revocable and what usage counts against — the two questions a signature cannot answer. The raw
token is stored nowhere; it is shown once, at creation.

Both deployments need the same `AXIOMETA_HEADLESS_SECRET`. Schema: `backend/sql/headless.sql`.
Supabase is optional on the service — without it the signature still gates access and usage simply
is not recorded, because a knowledge fetch must never fail over an analytics table. With no secret
set at all the service stays open rather than locking everyone out over a missing env var.

Board knowledge is authored once, in `backend/knowledge/`. `build_knowledge.py` is the only bridge:
it copies the hardware payload here and **deletes** anything carrying a `%%TOKEN%%` — those are
build-time substitutions belonging to a browser product this one is not part of. Deleted, not
reworded: hardware knowledge is pins, buses, addresses, libraries, init and timing, and a placeholder
for someone else's build step is none of those. Everything else passes through as written. Run
`--check` in CI.

## Boards

| Board | Silicon | Upload |
|---|---|---|
| Genesis One / Genesis Mini | ESP32-S3 | `upload` |
| XIAO Shield (ESP32-S3) | ESP32-S3 | `upload` |
| XIAO Shield (nRF52840) | nRF52840 | `upload` (Seeed nRF52 core) |
| Pi HAT | RP2040 | `upload` (mpremote over the Pi UART) |

Verbs are facts of the (board, language), read from `board.json` — not a list in this README.

Python 3.9+. `pyserial` is the only dependency; the build tools install into the private prefix.
