Users and Calibration Data

A user profile is a local record of one person's calibration data. The SDK scopes hand model calibration and tactile models per profile, so a shared glove can hold a personal calibration for each person, and you can carry a calibration between machines. wuji user manages these profiles. A profile is identified by its name. Every subcommand is a local operation under ~/.wuji/sdk and does not connect to a device. All subcommands support --json.

Why Profiles Matter for Calibration

Hand model calibration writes a per-profile URDF. The default user cannot run hand model calibration — create and switch to a named profile first. Tactile calibration is device-owned and does not require a named profile.

wuji user create alice --switch   # create and activate in one step
wuji calib hand-model              # now calibration is allowed

Managing Profiles

wuji user list                    # list profiles, '*' marks the current one
wuji user create alice -d "note"   # create (-d adds a description, does not switch unless --switch)
wuji user switch [alice]          # activate a profile or open the terminal selector
wuji user rename alice alice2     # rename and keep the calibration data
wuji user delete [alice]          # select and delete a profile and all its data (asks first)
wuji user show [alice]            # show a profile's calibration (defaults to current)

Names must be 1–32 characters of letters, digits, _, or -, and must not start with -. list marks the current profile with *, marks Default as not calibratable, and shows each named profile's left/right calibration state. show lists the hand model for each hand (state, file, size, time) and any tactile models grouped by device serial number. A device whose model files are incomplete is flagged with the missing file names, distinct from a device that was never calibrated.

In a terminal, switch without a name opens a profile selector. delete without a name opens a selector that excludes Default, marks the current profile, and starts on Cancel operation. After selection, delete prints what will be removed, suggests wuji user export for a backup, and asks for confirmation with No selected by default. Outside a terminal, deletion requires both an explicit profile name and --yes. The Default user cannot be deleted or renamed. Deleting the current user resets the current profile to Default.

Moving Calibration Between Machines

Calibration data—the per-profile hand-model URDFs plus each glove's tactile model, tactile parameters, and latest complete tactile run—travels as a single .zip bundle.

Export

wuji user export ./alice.zip      # write a .zip
wuji user export ./out-dir/       # an existing directory auto-names calib_bundle_<name>_<ts>.zip
wuji user export ./alice.zip --force   # overwrite an existing file

Export always operates on the current user. When the target is a directory, it must already exist — otherwise the command exits with code 1. In a terminal, exporting over an existing file asks for confirmation with No selected by default. Structured or redirected output requires --force. If the current profile has no calibration artifacts, no empty bundle is created: the command asks you to calibrate first and exits with code 1. On a named profile, run wuji calib hand-model to produce artifacts. Default can't run hand model calibration — create and switch to a named profile first, or run device-scoped tactile calibration instead.

A tactile model consists of three files: contact.safetensors, contact.npz, and contact.json. A model missing any of them is incomplete and is not bundled — the export listing marks it as skipped and names the missing files instead of dropping it silently. When the current profile has only incomplete tactile models, the error names the device SN and the missing files and asks you to rerun wuji calib tactile for those devices, also exiting with code 1.

Import

wuji user import ./alice.zip --preview             # inspect only, no changes
wuji user import ./alice.zip                        # preview, then confirm
wuji user import ./alice.zip --yes                  # import without the prompt
wuji user import ./alice.zip --as bob               # import into a new profile

Import operates on the current user or a newly created profile with --as <name>. After a successful import into a new profile, that profile becomes current. The terminal flow previews the source user, bundle contents, and conflicts. If the current profile has conflicting calibration artifacts and --as isn't set, choose to overwrite the current profile, create a new profile, or cancel. Otherwise, confirm the target profile before importing. Structured or redirected output requires --preview for inspection or --yes to write. Default cannot accept a bundle that contains a hand model. Pass --as <name>, or create and switch to a named profile before importing. An imported hand model is hot-reloaded without reconnecting the glove. An imported tactile model is reloaded automatically if that glove is connected and otherwise loads at its next connection. When the bundle comes from a different user and the target already has calibration artifacts, those artifacts are backed up under calibration-import-backups/ before they are overwritten. Empty profiles do not create empty backup directories. Backups are retained until removed manually.

The preview and import listings report every skipped tactile model with its reason: the bundle's model files are incomplete, the bundle carries no model for that device, or the bundle carries model files that its manifest doesn't declare. Artifacts the manifest doesn't declare are never installed — the listing now reports them instead of dropping them silently.

Automation

--json prints one document per command, and errors print {"error":{"code":…,"message":…}}. For a non-interactive import, use --preview to inspect without changes or --yes to apply the import. A non-interactive delete requires both an explicit profile name and --yes. Delete does not support --preview.

Under --json, create, switch, rename, and delete always include a current_user field that tells you which profile is active after the command finishes, so a script never needs a follow-up user list. rename also reports previous_name (the name before the rename) and name (the new name):

$ wuji user rename alice alice2 --json
{
  "action": "renamed",
  "name": "alice2",
  "previous_name": "alice",
  "current_user": "alice2"
}

show --json adds missing_model_files (the missing file names) to an incomplete tactile model. Skipped component rows in the export, import, and import --preview listings carry reason and an optional detail, where detail adds specifics such as the missing file names. For tactile models, the export listing only reports incomplete_model (model files incomplete), while the import and preview listings can also report not_in_bundle (no model in the bundle) and not_declared_in_manifest (not declared by the manifest).

Hand-model components can also report these reason values:

  • legacy_hand_model_ignored: The device-scoped hand model in bundle manifest version 1 or 2 isn't installed into a user profile
  • default_user_hand_model_disabled: The target is Default, which can't hold a hand model

If a bundle contains a per-user, per-hand model and targets Default, the CLI exits with code 5 before writing data.

// show --json: an incomplete tactile model entry (inside the tactile array)
{
  "sn": "<SN>",
  "calibrated": false,
  "missing_model_files": ["contact.npz", "contact.json"]
}
// export/import/preview listings: a skipped component row
{
  "name": "tactile.model",
  "device_sn": "<SN>",
  "state": "skipped",
  "reason": "incomplete_model",
  "detail": "missing contact.npz, contact.json"
}

Exit codes are specialized:

Exit Code (error.code)Meaning
0Success (including a no-op switch to the current user)
1Other runtime failure, including exporting a profile with no calibration data
2Invalid user name
3User already exists
4User not found
5Default-user protection (delete/rename Default, hand model calibration as the default user, or importing a bundle with a hand model into Default)
6Bundle file not found
7Bundle invalid or incompatible version
8Export target already exists (use --force)
9Cancelled at confirmation
Subscribe to Updates