A wireframe diagram of the orb

Introduction

Welcome! This book serves as the spot that the Worldcoin Project hosts its documentation for developing software for the orb.

It also provides an inside look at our development practices, which helps increase transparency of the project and provide foundations for other contributors to the project to build on top of.

Who is this for?

The target audience of this documentation is for contributors to the orb-software repo or any of the other open source repos that pertain to the orb. We plan to accept contributions at a later date, but do not have bandwidth to review PRs currently.

Likewise, we are providing source code and documentation for the benefit of the community, but cannot commit to any SemVer or API stability guarantees. Be warned: we may change things in a backwards-incompatible way at any time!

Where is the code?

See the orb-software repo for the code.

This is a living document. If you are a contributor and wish to improve the documentation, simply open a PR! The source code for the mdBook lives here.

However, spam/noise/typo PRs will be ignored. Especially those from bots. Do not farm green github squares from us.

Initial repo setup

To be able to build the code, there is some first-time setup required. There are two options:

Set up nix + direnv (the developer environment)

We use nix to manage all of the dependencies during development. While most of the software can use convnetional rust tools like cargo, we do have a few additional dependencies. Instead of apt-installing them, we use nix as the package manager, and use direnv to handle automatically activating a developer shell. The process to install and configure these two tools is as follows:

  1. Install nix. This works for both mac and linux, if you are using a windows machine, you must first set up WSL2.
  2. Ensure that you have these lines in your ~/.config/nix/nix.conf or /etc/nix/nix.conf. This is done automatically by the above installer:
    experimental-features = nix-command flakes
    max-jobs = auto
    
    You can check that things work by running nix run nixpkgs#hello
  3. Install direnv: nix profile install nixpkgs#direnv
  4. Hook direnv into your shell.
  5. Set up your personalized .envrc file by running cp .envrc.example .envrc. You can customize this file if you wish. We recommend filling in your cachix token if you have one. If prompted, don't run direnv allow yet, follow step 6 first. Otherwise you'll get a bunch of errors.
  6. Follow the instructions on vendoring proprietary SDKs in the subsequent section.
  7. Run direnv allow in the repository's root directory. Direnv will then automatically use the .envrc file you set up any time you cd into the directory.
  8. If you are on macos, run the following:
    brew install dbus
    brew services start dbus
    
  9. Install git lfs:
    git lfs install
    git lfs pull
    

Set up devcontainer

If you are using devcontainer with with or without vscode, you could use the provided devcontainer.json.

  1. Download the Seek Thermal Sdk and save it in .devcontainer/Seek_Thermal_SDK_4.1.0.0.zip
  2. Fire-up your devcontainer

Vendoring proprietary SDKs

Although all of Worldcoin's code in the orb-software repo is open source, some of the sensors on the orb rely on proprietary SDKs provided by their hardware vendors. Luckily, these are accessible without any cost, they are just annoying to get and are not themselves open source.

To get started, you will need to download these SDKs. The process for this depends on if you are officially affiliated with Worldcoin.

If you have access to Worldcoin private repos

  1. Create a personal access token from github to allow you to use private git repos over HTTPS.
  2. Append the following to your ~/.config/nix/nix.conf:
    access-tokens =
    github.com=github_pat_YOUR_ACCESS_TOKEN_HERE
    
  3. Test everything works so far by running nix flake metadata github:worldcoin/priv-orb-core. You should see a tree of info. If not, you probably don't have your personal access token set up right - post in slack for help.

If you don't have access to Worldcoin private repos

  1. Go to https://developer.thermal.com and create a developer account. Getting the SDK can take several days for Seek Thermal to approve access. In the meantime, you can skip steps 2 and 3.
  2. Download the 4.1.0.0 version of the SDK (its in the developer forums).
  3. Extract its contents, and note down the dir that contains the Seek_Thermal_SDK_4.1.0.0 dir.
  4. modify your .envrc like this: use flake . --override-input seekSdk "PATH_FROM_STEP_3". If you don't yet have access to the SDK, just provide a path to an empty directory.

Setting up AWS Credentials

[!NOTE] This section only applies to developers affiliated with the worldcoin organization.

Certain tools, including orb-tools, orb-hil, orb-bidiff-cli, cargo x optee ta sign and the official aws cli require setting up AWS credentials to use them.

While its always possible to export the credentials on the command line, its typically easier to leverage AWS's official "profile" system. Profiles are controled with the AWS_PROFILE environment variable, and configured under the ~/.aws directory.

For the intended contents of ~/.aws/config, see the internal docs.

You can now chose the appropriate aws profile for any CLI tool by passing the AWS_PROFILE=<profilename> env var in any aws-related tasks.

The available profiles above are:

  • hil for the orb-hil cli
  • bidiff-{stage,prod} to bidiff OTAs with the orb-bidiff-cli
  • trustzone-{stage,prod} to sign optee TAs with cargo x optee ta sign

Examples

For example, to use the HIL CLI:

AWS_PROFILE=hil aws sso login --use-device-code
AWS_PROFILE=hil cargo run -p orb-hil

To diff prod OTAs:

AWS_PROFILE=bidiff-prod aws sso login --use-device-code
AWS_PROFILE=bidiff-prod cargo run -p orb-bidiff-cli

How to develop and build code

Make sure you followed the first time setup instructions.

Building

We use cargo zigbuild for most things. The following cross-compiles a binary in the foobar crate to the orb. Replace foobar with the crate that you wish to build:

cargo zigbuild --target aarch64-unknown-linux-gnu --release -p foobar

You can also build code faster with cargo check, since it skips the linking step. Try running cargo check -p foobar.

Testing the code

Unlike building the code, tests are expected to run on the same target as the host. But not all tests are possible on every target.

IF it is supported, you can run cargo x t -p foobar. Use cargo x tw -p foobar to watch and rerun the tests. Both aliases run nextest with all features enabled. Support varies from crate to crate.

Running tests locally

Run cargo x t --all-targets -p foobar for any crate named foobar, or cargo x t --workspace --all-targets to test all crates. Use cargo x tw with the same arguments to watch and rerun tests. Both aliases run nextest with all features enabled. Some of our crates can only build when targeting Linux, so on macOS you will need to use the -p version or one of the Docker runners below.

You can also resort to cross compiling to linux and then running your tests in docker. There are two ways to do this:

Using a container based on a Dockerfile

A limited subset of tests can use a container built from a Dockerfile at docker/Dockerfile. You can choose to run tests this way with the following command:

RUSTFLAGS='--cfg docker_runner' cargo x t --target aarch64-unknown-linux-gnu --workspace --all-targets

Using a container built from nix directly

More (possibly all) tests can be run by using a container built using docker-tools. However, this requires you to have a linux remote builder runner for nix set up. The easiest way to do this is to use the linux-builder feature of nix-darwin. After setting up nix-darwin and enabling the linux-builder setting in your configuration.nix, you can run:

RUSTFLAGS='--cfg nix_docker_runner' cargo x t --target aarch64-unknown-linux-gnu --workspace --all-targets

Note that the only difference between this command and the other one is that the config flag for cargo is prefixed with nix_.

Running the code on an orb

For binaries that are intended to run on the orb, you can take your cross-compiled binary, and scp it onto the orb. You can either use teleport (if you have access) via tsh scp or you can get the orb's ip address and directly scp it on, with the worldcoin user.

If you choose the scp route without teleport, you will need to know the password for the worldcoin user. Note that this password is only for dev orbs, orbs used in prod are not accessible without teleport and logging in with a password is disabled.

Debugging

Tokio Console

Some of the binaries have support for tokio console. This is useful when debugging async code. Arguably the most useful thing to use it for is to see things like histograms of poll() latencies, which can reveal when one is accidentally blocking in async code. Double check that the binary you wish to debug actually supports tokio console - support has to be manually added, it isn't magically available by default.

To use tokio console, you will need to scp a cross-compiled tokio-console binary to the orb. To do this, just clone the repo and use cargo zigbuild --target aarch64-unknown-linux-gnu --release --bin tokio-console, then scp it over.

Note: tokio-console supports remote debugging via grpc, but I haven't figured out how to get the orb to allow that yet - I assume we have a firewall in place to prevent arbitrary tcp access, even in dev orbs.

Then, you must build the binary you want to debug unstable tokio features enabled. To do this, uncomment the line in .cargo/config.toml about tokio unstable.

Finally, make sure that the binary has the appropriate RUST_LOG level set up. try using RUST_LOG="info,tokio=trace,runtime=trace".

Finally, run your compiled binary and the compiled tokio-console binary on the orb. You should see a nice TUI.

Note that it is recommended but not required to have symbols present to improve the readability of debugging.

Android

Cross-compiling this workspace to aarch64-linux-android, and packaging binaries into signed .apex files.

Setup

Enter the dev shell (nix develop or direnv) - it wires up the NDK toolchain env vars automatically. Nothing else to install.

Build for Android

cargo x android-build          # debug
cargo x android-build --release

Builds the whole workspace for aarch64-linux-android, skipping crates that don't support it (see [package.metadata.orb] unsupported_targets in their Cargo.toml - usually dbus/systemd/gstreamer-dependent crates).

Package into .apex

cargo x android-apex               # every crate
cargo x android-apex orb-foo       # just one crate
cargo x android-apex --release

Requires an x86_64-linux host and nix on PATH (fetches/builds the build-apex flake package on first run). Output lands in target/android-apex/<crate>.apex, signed with AOSP's public test key - never a real release signature.

Install onto a device

cargo x android-deploy               # every crate
cargo x android-deploy orb-foo       # just one crate
cargo x android-deploy orb-foo --release

Runs android-apex under the hood, then installs each resulting .apex via adb install -t -r -g --force-non-staged, so it's usable immediately - no reboot required. Needs a device reachable over adb (same x86_64-linux + nix requirement as android-apex also applies here).

Gotchas

  • Not every crate builds for Android.
  • The manifest name, init script, and SELinux context are still placeholders (see TODOs in xtask/src/cmd/android.rs) - the .apex installs fine, but the packaged daemon won't actually start under init on a real device yet.

How we do open source

Worldcoin is committed to building a fully open source, decentralized ecosystem. In service of this goal, the entirety of the orb-software repo is open source under an MIT/Apache 2.0 dual license. You can read more about the project's open sourcing efforts here.

All source code for the Worldcoin Project lives under the worldcoin github organizaton.

Overview of private repos

To the maximum extent possible, we put all public code in the orb-software and orb-firmware repos. But we also maintain private repos, which contain code that is responsible for fraud detection or uses third party SDKs that we do not have a license to open source.

The most notable private repos are:

  • priv-orb-firmware. This repo contains the fraud sensitive parts of the firmware. It consumes the public orb-firmware repo as a dpenedency.
  • orb-internal. This repo contains the fraud sensitive parts of the user-space software. It consumes the public orb-software repo as a dependency.
  • priv-orb-core. This repo is the mainline branch of orb-core. Unlike the other repos, this is a fork of its public counterpart, orb-core. The public repo is therefore inherently less up to date and doesn't retain git history, as its code has all fraud-related codepaths manually deleted. One of the long-term goals is for these two repos to become un-forked, and most code consolidated into orb-software so that we can transition to developing orb-core directly in the open.
  • trustzone. This repo contains code related to the secure operating system OP-TEE that runs alongside linux inside ARM TrustZone. We plan to open source the OP-TEE CAs and TAs at some point in the future.-
  • orb-os. This repo is where we build the operating system image that runs on the orb. It consumes artifacts from all the other repos to assemble one final image.

Over-The-Air Updates (OTAs)

Overview of software components

The OTA system for the orb is comprised of several parts. All components are FOSS unless stated otherwise. Backend infrastructure is owned by Worldcoin Foundation and operated by Tools For Humanity, unless otherwise noted.

It is a long term goal to make these components FOSS, and decentralize them as much as possible.

OTA Consumption (On the orb):

OTA Production (Backend)

  • orb-os repo: Not yet FOSS 😢. Contains build scripts and CI to produce the custom debian based linux distro we ship on orbs.
  • orb-bidiff-cli: Produces binary diffs of OTAs for download size reduction.
  • orb-updates-lambda: Not FOSS 😢. Legacy golang lambda that runs when orb-os builds an OTA, to post-process it.
  • orb-manager: Not FOSS 😢. Legacy golang endpoints for OTA updates being migrated to orb-fleet-backend.

OTA Consumption (Backend)

  • orb-manager: see above.
  • orb-fleet-backend: Not FOSS 😢. New rust/axum service that will manage orbs.
  • AWS S3 buckets: Used to persist orb-os builds, OTAs, and bidiffs.
  • MongoDB: Tracks various information about OTAs and which orbs they are assigned to.

OTA structure

OTAs are comprised of a claim.json, and a list of binary files which we refer to as "components".

Claim structure

The claim.json can also be divided into three main parts, the manifest and the sources.

  • The manifest field, which contains metadata about how a component should be installed, as well as integrity information such as the hash of the component, its size, etc.
  • The sources field, which contains metadata about the compressed version of components, along with where they can be downloaded. These also have hashes and other integrity information.
  • The signature field, which enables the update agent to verify that the manifest has not been tampered with. This signature protects only the manifest, it does not protect the rest of the claim or the sources. Note that most of the orbs secure boot guarantees actually come from other places like dm-verity and our secure boot architecture, not from this manifest signature. In other words, the manifest signature is a nice "bonus" security measure.

When stored on s3, typically all of the compressed components (the sources), as well as the claim.json, are stored together in a "directory".

What is a component?

Once the source for a component is downloaded and potentially decompressed, it will be installed differently depending on the component type. Typically these components are things like partitions that should be dded to disk, firmware blobs to be sent over CAN, etc.

For the most comprehensive documentation, see the Component enum.

How do Partial OTAs work?

A partial OTA is a method of reducing the size of an OTA by sending only a subset of the full set of components in an OTA. Partial OTAs rely on shaky promises of reproducibility in orb-os, where we hope that certain partitions that the build produced didn't change, and therefore we can get away with not including the unchanged partitions as components in the OTA.

With the advent of binary diffing, partial OTAs are essentially unecessary. They are also even less useful on diamond orbs, whose root file system is mostly bundled into a single, really large component instead of multiple overlayfs partitions.

How do Binary Diffs work?

A component that is binary diffed is no different from a regular component, it just has a different MIME type - application/zstd-bidiff. Like GPT components, these are essentially just partition contents + the label of the partition. When "extracting" a bidiff component we:

  • inspect the component's label, to find a matching partition on the current booted slot which will become the base against which the patch will be applied.
  • stream the component through a zstd decompressor and the bipatch crate, writing the result out to the same location on the SSD that any other component source gets extracted to.
  • Proceed as normal, just like any other extracted component.

Binary Diffing CLI

A full size orb-os image can often be 5-6.5 GiB in size. Binary diffing is used as a compression mechanism, to reduce OTA sizes by only sending to orbs a "binary diff".

What is a Binary Diff

A binary diff is analagous to a diff in git, except instead of operating at the textual level, it operates at the bit/binary level.

The orb uses the bidiff and bipatch crates to generate and apply binary diffs, in addition to our own modifications to better handle squashfs files.

Further documentation on how bidiff, bipatch, and orb-bidiff-squashfs work can be found in their respective crates.

See also OTA Structure for more information on how binary diffs are represented in an OTA.

How to produce an OTA that uses binary diffs?

You can use either orb-tools bidiff or orb-bidiff-cli - both ways of accessing the cli are equivalent. Please refer to the documentation of the tool's --help interface for the most up-to-date docs.

Be sure that your AWS credentials are configured - you can follow the same instructions from orb-hil.

This CLI will be able to retrive the full-size OTAs from several places:

  • ota://X.Y.Z+whatever to download from s3 via the orb-os OTA version number
  • s3://foo/bar/ to download from s3 via a S3 URI
  • or a local file path

The CLI will take several minutes to run, and then produces a new OTA directory which contains all the components and a new, patched claim.json.

To see what the diffing process looks like, see this asciinema recording:

How to get the orb to OTA with a binary diff?

Right now the backend doesn't support binary diffs yet, this is still WIP. In the meantime, you can scp -r the contents of the directory that orb-bidiff-cli produced onto your orb, typically onto the ssd at /mnt/scratch/my-ota.

Then invoke the update agent with:

cd /mnt/scratch/my-ota
sudo /usr/local/bin/orb-update-agent \
  --nodbus \
  --orb-id $ORB_ID \
  --update-location /mnt/scratch/my-ota/claim.json

Hardware In Loop

Developing for the orb generally requires access to an orb. To make life easy, as well as to enable automated tests, we use an x86 linux machine as a host, which attaches to an orb via a number of hardware peripherals. We created the orb-hil cli tool to leverage this known hardware setup to perform a number of common, useful actions.

Getting an x86 Linux Machine

Technically, any x86 linux machine will do. However, we recommend using an ASUS/Intel NUC due to its compact form factor.

The Linux installation needs:

  • Access to the various attached usb devices without sudo, i.e. udev rules configured
  • Access to serial without sudo
  • Various packages (awscli2, usbutils, etc)
  • Teleport
  • Github self-hosted runner (if using this in CI).

To make this setup easy, we have a nix config that sets all of this up. BUT you could use regular ubuntu, or some other linux distro instead.

orb-hil cli

There is a CLI tool to facilitate hardware-in-loop operations. This tool lives in the orb-software repo and releases can be downloaded here.

It is a single, statically linked CLI tool with lots of features helpful for development:

  • Rebooting orbs into either normal or recovery mode
  • Flashing orbs (including downloading from S3, extraction, etc)
  • Executing commands over serial, SSH, or Teleport
  • Automating the login process over serial

Required peripherals

Different orb-hil subcommands require different hardware peripherals. We strongly recommend at least getting an x86 linux machine and a serial adapter.

Here are the different hardware peripherals necessary for the different subcommands of orb-hil:

  • orb-hil flash: x86 linux machine
  • orb-hil reboot: Serial adapter.
  • orb-hil login: Serial adapter.
  • orb-hil cmd: Serial adapter or network access (SSH/Teleport).

Logging in to AWS

The flash subcommand can download S3 urls. To set this up, we recommend following the instructions to set up aws. Then you can run

AWS_PROFILE=hil aws sso login # refresh your credentials for the hil profile
AWS_PROFILE=hil cargo run -p orb-hil # tell the orb-hil cli to use the hil profile

Software components of the orb

The orb consists of several software components. This section of the book provides a place to describe all of these different components.

See the individual sections in the table of contents to read more.

Orb Core

orb-core contains the core rust application responsible for verifying users' World IDs.

The binaries controlling the orb are found in src/bin/:

  • src/bin/orb-core.rs: the production binary, which runs verifications in the field.
  • src/bin/orb-backend-connect.rs: a binary to ensure backend connectivity by scanning a WiFi QR code and establishing the WiFi connection as long as the backend is not reachable.

Code Overview

Overview of the do_signup function:

flowchart TD
    A[Start Signup] --> B{Scan Operator QR Code}
    B -->|Success| C{Scan User QR Code}
    B -->|Failure| Z[End Signup]
    C -->|Success| D{Detect Face}
    C -->|Failure| Z
    D -->|Detected| E[Start Image Notary]
    D -->|Not Detected| Z
    E --> F[Biometric Capture]
    F --> G[Stop Image Notary]
    G --> H[Biometric Pipeline]
    H --> I{Detect Fraud}
    I -->|No Fraud| J[Enroll User]
    I -->|Fraud Detected| K[Mark as Fraud]
    J -->|Success| L[Mark Signup as Successful]
    J -->|Failure| M[Mark Signup as Failed]
    K --> N[Upload Debug Report and Opt-in Images]
    L --> N
    M --> N
    N --> Z

State of open sourcing

There are two orb-cores: the public one at worldcoin/orb-core and the private one at worldcoin/priv-orb-core. Today, the public repo is a manually stripped down version of the private one. This is done to remove code paths that could reveal the types of fraud detection that we perform. Long term, we plan to un-fork these two repos such that the public code lives in worldcoin/orb-software and the private code is only minimal additional code, which consumes the public code as a dependency. This will ensure that most code we develop is done directly in the open, where main lives in a public repo.

See how we do open source for more context.

Orb Management

This section documents tools and workflows used to generate, and register Orb devices across various platforms.

Included Tools

  • Orb Registration Script: A Python script that handles Orb provisioning and registration for both Pearl and Diamond platforms.

Orb Registration Script

A python script for generating and registering Orb devices across both Pearl and Diamond platforms with MongoDB and Core-App.

Overview

The script orb-registration.py (scripts/orb-registration/orb-registration.py) is a rewrite of the original gen-orb-id.sh and register-mongo.sh that supports both Pearl and Diamond orb platforms in a single, dependency-free Python implementation.

Key Features:

  • Dual Platform Support: Handles both Pearl (with artifact generation) and Diamond (registration-only) workflows
  • Zero Dependencies: Uses only Python standard library - no external packages required

Requirements

Python: Python 3.6 or higher (uses only standard library)

System Dependencies (must be available in PATH):

  • ssh-keygen - SSH key generation
  • mke2fs - ext4 filesystem creation
  • tune2fs - filesystem tuning
  • mount/umount - image mounting capabilities
  • install - file installation with permissions
  • setfacl - ACL support
  • sync - filesystem synchronization
  • cloudflared - Cloudflare Access authentication

Environment Variables:

  • FM_CLI_ORB_MANAGER_INTERNAL_TOKEN - MongoDB bearer token (can be overridden with --mongo-token)
  • HARDWARE_TOKEN_PRODUCTION - Core-App bearer token (can be overridden with --core-token)

Installation

  1. Make the script executable:

    chmod +x orb-registration.py
    
  2. Ensure system dependencies are installed:

    # Ubuntu/Debian
    sudo apt-get install e2fsprogs acl cloudflared
    
    
    
  3. Set up environment variables:

    export FM_CLI_ORB_MANAGER_INTERNAL_TOKEN="your_mongo_token_here"
    export HARDWARE_TOKEN_PRODUCTION="your_core_app_token_here"
    

Usage

Basic Command Structure

./orb-registration.py --platform {pearl|diamond} --backend {stage|prod} --release {dev|prod} --hardware-version HARDWARE_VERSION [additional options]

Required Arguments

  • --platform: Platform type (pearl or diamond)
  • --backend: Backend environment (stage or prod)
  • --release: Release type (dev or prod)
  • --hardware-version: Hardware version with platform prefix (e.g., PEARL_EVT1, DIAMOND_EVT2)

Optional Arguments

  • --channel: Channel for orb registration (default: general for prod, internal-testing for stage)
  • --mongo-token: MongoDB bearer token (overrides environment variable)
  • --core-token: Core-App bearer token (overrides environment variable)

Pearl Platform Options

  • --count: Number of orbs to generate (default: 1)

Diamond Platform Options

  • --input-file: Input file containing orb IDs or orb ID+name pairs
  • --input-format: Format of input file (ids or pairs, default: ids)
  • orb_ids: Direct orb IDs as positional arguments (alternative to --input-file)

Platform-Specific Workflows

Pearl Platform

Pearl orbs require complete artifact generation including SSH keys, persistent images, and registration in both systems.

What Pearl workflow does:

  1. Generates SSH keypair and derives orb-id (SHA256 hash)
  2. Registers orb in MongoDB Management API
  3. Sets orb channel
  4. Retrieves orb token
  5. Creates persistent filesystem images (1MB and 10MB variants)
  6. Installs baseline configuration files
  7. Generates per-orb artifacts with embedded orb-name and token
  8. Registers orb in Core-App

Generated artifacts (stored in artifacts/{orb-id}/):

  • uid - Private SSH key
  • uid.pub - Public SSH key
  • orb-name - Assigned orb name
  • token - Orb authentication token
  • persistent.img - 1MB persistent filesystem image
  • persistent-journaled.img - 10MB persistent filesystem image with journal

Diamond Platform

Diamond orbs only require registration without artifact generation.

What Diamond workflow does:

  1. Processes orb IDs from input (file or CLI arguments)
  2. Registers each orb in MongoDB Management API (if using IDs-only format)
  3. Registers each orb in Core-App

Input formats:

  • IDs format: File contains one orb ID per line, script gets orb-name from MongoDB
  • Pairs format: File contains orb-id orb-name pairs, script skips MongoDB registration

Detailed Usage Examples

Pearl Platform Examples

Generate Single Pearl Orb (Stage Environment)

./orb-registration.py \
    --platform pearl \
    --backend stage \
    --release dev \
    --hardware-version PEARL_EVT1

Generate Multiple Pearl Orbs (Production Environment)

./orb-registration.py \
    --platform pearl \
    --backend prod \
    --release prod \
    --hardware-version PEARL_EVT1 \
    --count 10 \
    --channel production-batch-1

Output:

  • Creates 10 separate artifact directories
  • Uses custom channel "production-batch-1"
  • Registers all orbs in production systems

Pearl with Custom Tokens

./orb-registration.py \
    --platform pearl \
    --backend prod \
    --release dev \
    --hardware-version PEARL_EVT1 \
    --count 5 \
    --mongo-token "custom_mongo_token" \
    --core-token "custom_core_token" \
    --channel development

Diamond Platform Examples

Register Diamond Orbs from File (IDs Only)

# Create input file
cat > diamond_orbs.txt << EOF
abc123def456
ghi789jkl012
mno345pqr678
EOF

./orb-registration.py \
    --platform diamond \
    --backend prod \
    --release prod \
    --hardware-version DIAMOND_EVT2 \
    --input-file diamond_orbs.txt \
    --channel diamond-production

What happens:

  • Reads orb IDs from diamond_orbs.txt
  • Registers each in MongoDB to get orb-name
  • Registers each in Core-App
  • No artifacts generated

Register Diamond Orbs with Pre-assigned Names

# Create input file with orb-id and orb-name pairs
cat > diamond_pairs.txt << EOF
abc123def456 diamond-orb-001
ghi789jkl012 diamond-orb-002
mno345pqr678 diamond-orb-003
EOF

./orb-registration.py \
    --platform diamond \
    --backend prod \
    --release prod \
    --hardware-version DIAMOND_EVT2 \
    --input-file diamond_pairs.txt \
    --input-format pairs \
    --channel diamond-custom

What happens:

  • Reads orb-id and orb-name pairs from file
  • Skips MongoDB registration (names already provided)
  • Registers directly in Core-App
  • Uses custom channel "diamond-custom"

Register Diamond Orbs via CLI Arguments

./orb-registration.py \
    --platform diamond \
    --backend stage \
    --release dev \
    --hardware-version DIAMOND_EVT2 \
    abc123def456 ghi789jkl012 mno345pqr678

What happens:

  • Processes orb IDs provided as CLI arguments
  • Registers in stage environment
  • Uses default stage channel "internal-testing"

File Structure

gen-device-unique/
├── orb-registration.py              # Main script
├── build/                     # Baseline configuration files
│   ├── components.json
│   ├── calibration.json
│   └── versions.json
├── artifacts/                 # Generated Pearl artifacts
│   └── [orb-id]/             # Per-orb artifact directory
│       ├── uid               # Private SSH key
│       ├── uid.pub           # Public SSH key
│       ├── orb-name          # Assigned orb name
│       ├── token             # Orb authentication token
│       ├── persistent.img    # 1MB filesystem image
│       └── persistent-journaled.img # 10MB filesystem image
└── README.md                 # This file

Channel Configuration

Stage Environment

  • Fixed Channel: internal-testing
  • Behavior: Channel cannot be overridden for stage environment
  • Usage: Primarily for internal testing and development

Production Environment

  • Default Channel: general
  • Customizable: Can be overridden with --channel argument
  • Usage: Flexible channel assignment for production deployments

Channel Examples:

# Uses default "general" channel
./orb-registration.py --platform pearl --backend prod --release prod --hardware-version PEARL_EVT1

# Uses custom channel
./orb-registration.py --platform pearl --backend prod --release prod --hardware-version PEARL_EVT1 --channel batch-2024-01

# Stage always uses "internal-testing" regardless of --channel
./orb-registration.py --platform pearl --backend stage --release dev --hardware-version PEARL_EVT1 --channel ignored

Error Handling

Common Error Scenarios

Already Registered Orb

[ERROR] Failed to register orb abc123def456 in MongoDB: HTTP 409 Conflict - {"error": "Orb already exists"}

Invalid Authentication

[ERROR] Failed to register orb abc123def456 in MongoDB: HTTP 401 Unauthorized - {"error": "Invalid token"}

Network Issues

[ERROR] Failed to register orb abc123def456 in Core-App: HTTP 500 Internal Server Error - {"error": "Database connection failed"}

Missing Dependencies

[ERROR] Command 'ssh-keygen' not found. Please install OpenSSH client.

API Endpoints

MongoDB Management API

  • Stage: https://management.internal.stage.orb.worldcoin.dev
  • Production: https://management.internal.orb.worldcoin.dev

Endpoints used:

  • POST /api/v1/orbs/{orb_id} - Register orb
  • POST /api/v1/orbs/{orb_id}/channel - Set channel
  • POST /api/v1/tokens?orbId={orb_id} - Get token

Core-App API

  • Endpoint: https://api.operator.worldcoin.org/v1/graphql
  • Method: GraphQL mutation InsertOrb

Troubleshooting

Common Issues

Permission Errors

# Ensure script is executable
chmod +x orb-registration.py

# Check mount permissions
sudo usermod -a -G disk $USER

Missing Environment Variables

# Check if tokens are set
echo $FM_CLI_ORB_MANAGER_INTERNAL_TOKEN
echo $HARDWARE_TOKEN_PRODUCTION

# Set if missing
export FM_CLI_ORB_MANAGER_INTERNAL_TOKEN="your_token"
export HARDWARE_TOKEN_PRODUCTION="your_token"

Alternatively pass them as input arguments

Cloudflared Issues

# Login to cloudflared
cloudflared access login --quiet https://management.internal.stage.orb.worldcoin.dev

# Check cloudflared status
cloudflared --version

File System Issues

# Check available space
df -h

# Check loop device availability
sudo losetup -a

Debug Mode

For detailed debugging, you can modify the script to enable debug logging:

# In orb-registration.py, change:
logger = generate_logger(logging.INFO)
# To:
logger = generate_logger(logging.DEBUG)