Metadata-Version: 2.4
Name: pymoku-sdk
Version: 0.5
Summary: CLI tool to create pymoku projects
Author-email: Ben Coughlan <ben@liquidinstruments.com>
Maintainer-email: Ben Coughlan <ben@liquidinstruments.com>
License-Expression: MIT
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pymoku>=4.7.1
Requires-Dist: pymoku-parts>=0.9
Requires-Dist: click
Requires-Dist: rich
Requires-Dist: Jinja2
Requires-Dist: cryptography
Requires-Dist: httpx
Requires-Dist: pywellen
Dynamic: license-file

# pymoku-sdk

SDK for developing custom slots for Moku devices. Provides:

- `pymokusdk` — CLI for scaffolding new projects, registering for cloud
  builds, and managing signing keys.
- `parts` — CLI for running simulations and building bitstreams (from
  `pymoku-parts`).
- `pymoku` — CLI for deploying barfiles, listing devices, and launching
  the GUI (from `pymoku`).
- `pymoku.sdk.*` — Python API that `parts.def` files import to declare
  build targets (`CocoTB`, `RMSynth`, `BarFile`, `get_platform`, …).

## Install

Three install paths, depending on how you manage Python environments.
All three put the same three CLIs at your disposal; the difference is
where the binaries land.

### `uv tool install` — CLIs on PATH, no per-project deps

Best if you're going to work on several slot projects and want the SDK
available outside any one of them. One install, all three CLIs:

    uv tool install pymoku[sdk] \
        --with-executables-from pymoku-sdk \
        --with-executables-from pymoku-parts

`uv tool install` by default only exposes the main package's own entry
points — `pymoku[sdk]` alone would link `pymoku` but leave `pymokusdk`
and `parts` stranded inside the tool env. The `--with-executables-from`
flag symlinks the named packages' entry points too, so all three CLIs
land in `~/.local/bin/`. They share one isolated env, which keeps
`pymoku-sdk` and `pymoku-parts` versions coherent.

`uv` will warn if `~/.local/bin/` isn't on your PATH and suggest
`uv tool update-shell` to fix it. Verify with:

    pymokusdk --version

Want a one-shot scaffold without persistent install? `uvx` runs tools
ephemerally:

    uvx --from pymoku-sdk pymokusdk new MySlot --hw mokugo

### `uv add` — pinned in your project's `uv.lock`

Best if you want the SDK version locked alongside your other deps. Run
inside an existing uv project:

    uv add pymoku[sdk]

The `[sdk]` extra pulls in `pymoku-sdk` and (transitively)
`pymoku-parts`. All three CLIs land in `<project>/.venv/bin/`, which is
**not** on your shell's PATH unless you activate the venv. Either:

    source .venv/bin/activate

…or prefix every command with `uv run`:

    uv run pymokusdk new ...
    uv run parts tests

Examples below use bare `pymokusdk`/`parts`/`pymoku`. Substitute the
`uv run` form throughout if you went this route and don't want to
activate.

### `pip install` — traditional

    pip install pymoku[sdk]

Inside an active virtualenv this gives you all three CLIs on PATH for
the lifetime of the env. `--user` puts them in `~/.local/bin/`.

## Sign in for cloud builds

CocoTB simulations and Vivado synthesis run remotely, so you don't need
a local Vivado install. Register once to get an API key:

    pymokusdk login

If you already have a key:

    pymokusdk login --api-key <my-api-key>

This writes `parts.toml` to the **current directory**, so run it from
your project root. From then on, `parts` routes `CocoTB` and
`VivadoStep`/`BitbinStep` targets through the cloud automatically.

To share one key across every project, copy that file to
`~/.config/parts/parts.toml` — both locations are read and merged, with
the project-local one winning.

Full setup path, `parts.toml` reference and troubleshooting:
`pymokusdk docs cloud-builds`.

## Signing keys

Barfiles deployed on a Moku must be signed — either by a Liquid
Instruments production key, or by a developer key that's been enabled
on the target device:

    pymokusdk keys create <my-key-name>

The resulting public key needs to be signed by Liquid Instruments to
enable specific devices. One-time setup per developer.

## Create a new project

    pymokusdk new MySlot --hw mokugo
    cd myslot

This scaffolds:

| File | Purpose |
|---|---|
| `vhdl/MySlotSlot.vhd` | Top-level slot entity |
| `python/myslot.py` | `Slot` subclass + register descriptors |
| `python/applet.py` | Placeholder PySide6 GUI |
| `python/__init__.py` | Plugin class (loaded from the barfile at runtime) |
| `tests/test_myslot.py` | CocoTB testbench |
| `parts.def` | Build targets — simulation, bitstream, Python plugin |

Re-running `pymokusdk new` against an existing directory skips files
that already exist, so it's safe to use for adding a new platform
(`--hw mokulab`, etc.) to an existing project.

## Run the simulation

From inside the project:

    parts tests

Per-test outputs land in `build/test-slot/`: `wave.ghw` (GTKWave
waveform) and `stdout.log` (execution log). VHDL compilation errors
print to the console; runtime CocoTB errors go to `stdout.log`.

## Build the bitstream

    parts mokugo python --stats

`mokugo` is the alias that builds every slot variant declared in
`parts.def` for that hardware (e.g. `mokugo-1`, `mokugo-2`). `python`
packages the Python plugin into a separate barfile that the device
loads at deploy time. `--stats` adds a CLB/DSP/BRAM/WNS summary per
slot.

Output barfiles land in `output/`.

## Platforms

`get_platform()` resolves a platform shell for slot synthesis. Order:

1. **Local build target** — When developing new platforms,`parts.def` files
   can register platforms as  global targets (e.g. `global_alias('mokugo-1', p1)`).
2. **Local checkpoint barfile** — prebuilt platform DCPs from
   `~/.pymoku/barfile_cache` or a `checkpoints/` directory alongside
   the project.
3. **Cloud checkpoint barfile** — downloaded on demand and cached
   locally for subsequent builds.

### Pinning a checkpoint version

    parts mokugo --platform-version 1.2.3    # exact version
    parts mokugo --platform-version latest   # newest available (default)

Ignored when step 1 wins.

### Listing what's available

    pymokusdk platforms              # all platforms + their cloud versions
    pymokusdk platforms mokugo       # one platform, with per-cell detail

## Deploy

### From Python

    import pymoku
    pymoku.plugins.DEV_CACHE = './output'
    moku = pymoku.connect('10.0.0.1')
    moku.deploy_platform('pymoku:platform_2')
    myslot = moku.deploy('custom:myslot')

The `myslot` object is constructed from your Python plugin (the barfile
present in DEV_CACHE) and attached to the live slot on the Moku. Methods
and register descriptors on it talk to the device directly.

### From the GUI

Install GUI support (`pip install pymoku[gui]` or
`uv add pymoku[gui]`), then:

    pymoku --dev output/

After connecting and deploying a platform, your custom instrument
appears in the functions palette. Launching it opens the applet you
defined in `python/applet.py` (defaults to a Python console).

## Troubleshooting

- **`pymokusdk: command not found`** — your install put the CLI in a
  venv that isn't activated, or in `~/.local/bin/` which isn't on PATH.
  See the install section above; with `uv tool install`, run
  `uv tool update-shell` and restart your shell.
- **`deploy('custom:foo')` fails with "not available for platform
  '<sha>'"** — the bar you built was against a different platform shell
  than the one currently deployed on the device. Either rebuild with
  `--platform-version` set to the device's checkpoint, or
  `deploy_platform()` to redeploy the target platform first.
