Build a Package

Write a command, bundle it, host a repo, and get it running on any RPCortex device.

Overview

RPCortex packages are standard ZIP archives renamed to .pkg. Each package contains your Python source files and a package.cfg metadata file. The package manager handles installation, command registration, and removal — no reboot needed.

What you need:

make_pkg.py PC-side tool that builds .pkg archives using ZIP STORED (no compression). Required for Pico-compatible packages.
Download make_pkg.py

Package Structure

A package is a directory with at least two files:

MyPackage/
  package.cfg       # required: metadata and command registration
  main.py           # your code (can be named anything)
  helpers.py        # optional: additional modules

The directory name becomes the archive prefix. make_pkg.py walks the entire directory tree, so subdirectories work too.

ZIP STORED only. MicroPython on Pico W does not always have zlib available. Packages must be built with no compression. make_pkg.py handles this automatically — do not use a standard ZIP tool or your package will fail to install on many devices.

package.cfg Reference

Plain text, one key per line, colon-separated. Lines starting with # are comments.

# RPCortex Package Config
pkg.name: MyPackage
pkg.dev:  yourname
pkg.ver:  1.0.0
pkg.dir:  /Packages/MyPackage
pkg.desc: One-line description shown in pkg list
pkg.cmd:  mycommand:/Packages/MyPackage/main.py:run
KeyRequiredDescription
pkg.nameYesDisplay name. Used by pkg info and pkg list.
pkg.devYesAuthor or maintainer.
pkg.verYesVersion string (e.g. 1.0.0). Used by pkg upgrade.
pkg.dirYesAbsolute install path on device (e.g. /Packages/MyPackage).
pkg.descYesShort description shown in search and list output.
pkg.cmdNoShell command registration (see below). Omit for library-only packages.

pkg.cmd format

One command per pkg.cmd line. Multiple commands are supported by repeating the key:

pkg.cmd: hello:/Packages/HelloWorld/main.py:hello
pkg.cmd: hello-verbose:/Packages/HelloWorld/main.py:hello_verbose

Format: <shell-command>:</absolute/path/to/file.py>:<function_name>

Writing Commands

Every command function receives a single args parameter containing everything the user typed after the command name, or None if nothing was given.

def mycommand(args=None):
    if args:
        # args is a plain string: "foo bar baz"
        parts = args.split(None, 1)
    else:
        # no arguments given
        pass

Output utilities

Import from RPCortex for colored, logged output:

import sys
if '/Core' not in sys.path:
    sys.path.append('/Core')

from RPCortex import ok, info, warn, error, multi, inpt
FunctionColorUse for
ok(msg)Green [OK]Success messages
info(msg)Blue [ i]Section headers, informational
warn(msg)Yellow [!]Non-fatal warnings
error(msg)Red [E]Recoverable errors
fatal(msg)Red [X]Critical failures
multi(msg)WhitePlain output, data lines
inpt(prompt)CyanInteractive user input

Rules for MicroPython compatibility

Building a .pkg

Run make_pkg.py from your PC, pointing it at your package directory:

python make_pkg.py packages/MyPackage
# or specify an output name:
python make_pkg.py packages/MyPackage mypackage.pkg

If no output path is given, the file is named after pkg.name from your package.cfg (lowercased).

Example output:

  + MyPackage/package.cfg
  + MyPackage/main.py

Created 'mypackage.pkg' (1842 bytes)
Compression: ZIP_STORED (Pico-compatible, no zlib needed)
Install on device: pkg install /path/to/mypackage.pkg
make_pkg.py requires only the Python 3 standard library (zipfile, os, sys). No dependencies to install.

Testing Locally

Copy the .pkg file to your device (via Thonny, mpremote, or ampy), then install it from the shell:

pkg install /mypackage.pkg

The command is registered immediately. Run it:

mycommand
mycommand some arguments here

Check it appears in the package list:

pkg list
pkg info MyPackage

To remove it:

pkg remove MyPackage

The command disappears from the shell immediately — no reboot needed.

Common issues

SymptomCauseFix
Install fails with zlib errorPackage was built with ZIP deflate compressionRebuild with make_pkg.py (uses ZIP_STORED)
Command not found after installpkg.cmd path or function name is wrongCheck the path in package.cfg matches the actual file on device
MemoryError during installHeap fragmented after other commandsRun freeup first, then retry
Function not callableWrong function name in pkg.cmdVerify the function name matches exactly (case-sensitive)

Hosting a Repo

A repo is a single JSON file accessible over HTTP or HTTPS. GitHub raw URLs, static hosting, and anything that returns Content-Type: application/json all work.

index.json format

{
  "name": "My Repo",
  "maintainer": "yourname",
  "packages": [
    {
      "name": "MyPackage",
      "ver": "1.0.0",
      "desc": "One-line description",
      "author": "yourname",
      "url": "https://example.com/repo/packages/mypackage.pkg"
    }
  ]
}
FieldDescription
nameRepo display name (shown during pkg update)
maintainerRepo owner
packages[].namePackage name (must match pkg.name in package.cfg)
packages[].verVersion string (used by pkg upgrade to detect updates)
packages[].descShown in pkg available and pkg search
packages[].authorPackage author
packages[].urlDirect download URL for the .pkg file

Hosting on GitHub

The simplest option: put index.json and your .pkg files in a GitHub repo, then use raw URLs:

# index.json URL (add this on the device):
https://raw.githubusercontent.com/yourname/my-rpc-repo/main/index.json

# .pkg URL in index.json:
https://raw.githubusercontent.com/yourname/my-rpc-repo/main/packages/mypackage.pkg
HTTPS on Pico 1 W: raw.githubusercontent.com uses HTTPS. TLS needs ~9.5 KB of contiguous heap. Run freeup before pkg update on a Pico 1. Pico 2 and ESP32 are not affected.

Adding your repo to a device

pkg repo add https://raw.githubusercontent.com/yourname/my-rpc-repo/main/index.json
pkg update
pkg available

Getting Listed in the Official Repo

The official RPCortex repo is hosted at rpc.novalabs.app/repo/index.json. To get your package listed:

  1. Make sure your package installs and runs cleanly on a Pico W (the primary target)
  2. Host your .pkg file somewhere with a stable URL (GitHub releases or raw works well)
  3. Open a pull request on GitHub adding an entry to website/repo/index.json
  4. Include your package name, version, description, author, and the URL of your hosted .pkg
{
  "name": "YourPackage",
  "ver": "1.0.0",
  "desc": "What your package does",
  "author": "yourname",
  "url": "https://your-host/yourpackage.pkg"
}

Full Example: HelloWorld

This is the reference sample package included in the repo.

File: HelloWorld/package.cfg

# RPCortex Package Config
pkg.name: HelloWorld
pkg.dev:  dash1101
pkg.ver:  1.0.1
pkg.dir:  /Packages/HelloWorld
pkg.desc: Sample demo package for RPCortex
pkg.cmd:  hello:/Packages/HelloWorld/main.py:hello

File: HelloWorld/main.py

# Desc: HelloWorld -- sample RPCortex package
# File: /Packages/HelloWorld/main.py
# Version: 1.0.1
# Author: dash1101

import sys
if '/Core' not in sys.path:
    sys.path.append('/Core')

from RPCortex import ok, multi


def hello(args=None):
    multi("")
    multi("  Hello from HelloWorld!")
    multi("  RPCortex package system is working correctly.")
    if args:
        multi("  You said: " + args)
    multi("")
    ok("HelloWorld v1.0.1")

Build it

python make_pkg.py HelloWorld
# Output: helloworld.pkg

Install and test on device

# Copy helloworld.pkg to device root, then in the shell:
pkg install /helloworld.pkg
hello
hello testing 1 2 3

Expected output


  Hello from HelloWorld!
  RPCortex package system is working correctly.

[OK] HelloWorld v1.0.1

RPCortex Nebula v0.8.1-beta2  •  by dash1101