PCLI2 Documentation

PCLI2 is the command-line client for the Physna public API: 3D geometry search, asset and folder management, metadata, and batch operations, with output that is built for scripts (JSON, CSV, Excel) as much as for people.

Chapters

Features

  • Nested sub-commands with short aliases (pcli2 asset ls, pcli2 folder rm)
  • Multiple environments (production, staging) and multiple tenants
  • OAuth2 client-credentials login with automatic token renewal
  • Asset upload, download, listing, deletion, reprocessing and thumbnails
  • Folder tree listing, creation, renaming, moving, bulk upload and download
  • Geometric, part and visual matching, single-asset or folder-wide, with CSV and Excel reports
  • Metadata fields: create, read, delete, bulk-load from CSV, infer from matches
  • Resumable runs: downloads skip files already on disk, uploads skip assets already in the folder, folder matches continue from a checkpoint file
  • Retries with backoff for transient failures, and exit codes that say what went wrong
  • Built for scripts: --no-input, --error-format json, --safe-csv, and pcli2 doctor for checking a setup

Start with the Installation Guide, then the Quick Start Guide.

Installation Guide

PCLI2 ships as pre-built binaries for macOS (Intel and Apple Silicon), Linux (x86_64 and aarch64) and Windows (x86_64). No Rust toolchain is needed unless you build from source.

Table of Contents

Installers

macOS and Linux: shell installer

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/jchultarsky101/pcli2/releases/latest/download/pcli2-installer.sh | sh

The script installs pcli2 and pcli2-update into ~/.cargo/bin (or the directory it reports) and offers to add it to your PATH.

macOS and Linux: Homebrew

Homebrew 6 refuses formulae from taps it has not been told to trust, so the first step is a one-time brew trust (per machine and user account):

brew trust jchultarsky101/pcli2
brew install jchultarsky101/pcli2/pcli2

Without it, brew install and every later brew upgrade pcli2 stop with "Refusing to load formula jchultarsky101/pcli2/pcli2 from untrusted tap". Homebrew 5 has no such check, but the first upgrade after moving to Homebrew 6 will. In CI, set HOMEBREW_NO_REQUIRE_TAP_TRUST=1 instead of trusting interactively.

Windows: PowerShell installer

powershell -ExecutionPolicy Bypass -c "irm https://github.com/jchultarsky101/pcli2/releases/latest/download/pcli2-installer.ps1 | iex"

Windows: MSI

Download pcli2-x86_64-pc-windows-msvc.msi from the latest release and run it.

Archives

Every release also carries plain archives (.tar.xz for macOS and Linux, .zip for Windows) with the binary inside. Extract it and put it on your PATH.

Verifying the Installation

pcli2 --version
pcli2 --help

Shell completions and man pages are generated by the binary itself:

pcli2 completions zsh > ~/.zfunc/_pcli2     # or bash, fish, elvish, powershell
pcli2 man --output-dir ./man

Updating

Installed withUpdate with
Shell or PowerShell installerpcli2-update
Homebrewbrew upgrade pcli2 (after the one-time brew trust jchultarsky101/pcli2 on Homebrew 6)
MSIDownload and run the newer MSI (the MSI does not ship the updater)

PCLI2 prints a one-line hint on stderr when a newer release exists (at most once a day, in terminal sessions only). Set PCLI2_NO_UPDATE_CHECK=1 to turn it off.

Building from Source

Requires a Rust toolchain (1.88 or newer) and, on Linux, pkg-config, libssl-dev and cmake.

git clone https://github.com/jchultarsky101/pcli2.git
cd pcli2
cargo build --release
# The executable is target/release/pcli2

PCLI2 is not published on crates.io, so cargo install pcli2 does not work.

Troubleshooting

  1. Command not found: the install directory is not on your PATH; the installer prints the directory it used.
  2. An old version keeps running: which -a pcli2 (or where pcli2 on Windows) lists every copy on the PATH; remove the stale one.
  3. Build failures from source: update Rust with rustup update stable.

If you are stuck, open an issue at GitHub Issues.

Quick Start Guide

This guide will help you get started with PCLI2 quickly by walking through common tasks.

Table of Contents

Authentication

Before using most PCLI2 commands, you need to authenticate with your Physna tenant. First, you'll need to obtain your API credentials.

Getting API Credentials

There are two methods to obtain your API credentials:

This is the newer, more user-friendly approach available to administrators:

  1. Log in to your Physna instance
  2. (Optional) Select a tenant from the tenant selector
  3. Click on Settings (the gear icon in the top-right corner)
  4. Navigate to the Users tab
  5. Create a new service account
  6. Record the Client ID and Client Secret for use with PCLI2

Method 2: Using the API Documentation Page (Legacy)

This is the original approach using the API documentation interface:

  1. Navigate to the Physna OpenAPI Documentation page
  2. Log in with your Physna credentials
  3. Locate and execute the POST /users/me/service-accounts endpoint
  4. Record the Client ID and Client Secret from the response

Logging In

Once you have your credentials, you can authenticate with PCLI2:

# Login interactively (prompts for the client ID and secret, with
# masked input so the secret never lands in your shell history)
pcli2 auth login

# Login with client credentials
pcli2 auth login --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET

# Verify authentication
pcli2 auth get

Basic Navigation

Learn to navigate your Physna tenant using PCLI2:

# List available tenants
pcli2 tenant list

# List folders in the root directory (shows only direct children, not entire subtree)
pcli2 folder list

# List folders in tree format to see the complete hierarchy
pcli2 folder list --format tree

# List assets in a specific folder
pcli2 asset list --folder-path /Home/MyFolder/

Working with Assets

Asset management is a core function of PCLI2. These commands allow you to upload, retrieve, organize, and maintain your 3D models and other assets in Physna.

Uploading Assets

The asset create command uploads individual files to your Physna tenant, placing them in the specified folder path. This is useful for adding single assets to your collection:

# Upload a single asset
pcli2 asset create --input path/to/my/model.stl --folder-path /Home/MyFolder/

# Replace an existing asset (deletes the old one first)
pcli2 asset create --input path/to/my/model.stl --folder-path /Home/MyFolder/ --override

# Replace an existing asset and keep its metadata
pcli2 asset create --input path/to/my/model.stl --folder-path /Home/MyFolder/ --override --restore-metadata

For bulk operations, asset create-batch allows you to upload multiple files at once using glob patterns:

# Upload multiple assets
pcli2 asset create-batch --input "models/*.stl" --folder-path /Home/BatchUpload/

Viewing and Managing Assets

Use these commands to inspect and manage your assets:

# View asset details
pcli2 asset get --path /Home/MyFolder/model.stl

# Delete an asset
pcli2 asset delete --path /Home/MyFolder/model.stl

Geometric Matching

Geometric matching is a powerful feature that allows you to find assets with similar 3D geometry in your Physna tenant. This is particularly useful for identifying duplicate parts, finding design variations, or discovering similar components across different projects.

# Find matches for a single asset
pcli2 asset geometric-match --path /Home/Folder/ReferenceModel.stl --threshold 85.0

# Find matches for all assets in a folder (parallel processing)
pcli2 folder geometric-match --folder-path /Home/SearchFolder/ --threshold 90.0 --format csv --progress

The threshold parameter controls the similarity requirement, where higher values (closer to 100) require closer matches. The progress flag provides visual feedback during long-running operations.

Metadata Operations

Metadata is essential for organizing and searching your assets effectively. PCLI2 supports comprehensive metadata operations including creating, retrieving, updating, and deleting asset metadata. Metadata helps you categorize, filter, and find assets based on custom properties like material, supplier, weight, or any other characteristic relevant to your workflow.

Creating and Updating Metadata

The metadata create command adds or updates a single metadata field on an asset. This is useful for setting specific properties on individual assets:

# Add or update a single metadata field on an asset
pcli2 asset metadata create --path "/Home/Folder/Model.stl" --name "Material" --value "Steel" --type "text"

# Add or update multiple metadata fields on an asset
pcli2 asset metadata create --path "/Home/Folder/Model.stl" --name "Weight" --value "15.5" --type "number"

Retrieving Metadata

Use the metadata get command to view all metadata associated with an asset:

# Get all metadata for an asset
pcli2 asset metadata get --path "/Home/Folder/Model.stl"

Deleting Metadata

The metadata delete command removes specific metadata fields from an asset without affecting other metadata on the same asset:

# Delete specific metadata fields from an asset
pcli2 asset metadata delete --path "/Home/Folder/Model.stl" --name "Material" --name "Weight"

# Delete metadata fields using comma-separated list
pcli2 asset metadata delete --path "/Home/Folder/Model.stl" --name "Material,Weight,Description"

Metadata Inference

Metadata inference automatically applies metadata from a reference asset to geometrically similar assets. This feature helps you efficiently propagate metadata across similar assets, reducing manual work and ensuring consistency in your asset database:

# Apply specific metadata fields from a reference asset to similar assets
pcli2 asset metadata inference --path /Home/Folder/ReferenceModel.stl --name "Material,Cost" --threshold 85.0

# Apply metadata recursively to create chains of similar assets

# Apply multiple metadata fields with different thresholds
pcli2 asset metadata inference --path /Home/Folder/ReferenceModel.stl --name "Material" --name "Finish" --name "Supplier" --threshold 80.0

The metadata operations help you efficiently manage your asset metadata, whether you need to add, update, retrieve, or delete specific metadata fields, or propagate metadata across geometrically similar assets.

Configuration

Manage your PCLI2 configuration:

# Where the configuration file is
pcli2 config get path

# Export configuration for backup
pcli2 config export --output my-config.yaml

Multi-Environment Configuration

PCLI2 supports multiple environment configurations, allowing you to easily switch between different Physna instances (e.g., development, staging, production):

# Add a new environment configuration
pcli2 env add --name "development" \
  --api-url "https://dev-api.physna.com/v3" \
  --ui-url "https://dev.physna.com" \
  --auth-url "https://dev-auth.physna.com/oauth2/token"

# Add a production environment
pcli2 env add --name "production" \
  --api-url "https://app-api.physna.com/v3" \
  --ui-url "https://app.physna.com" \
  --auth-url "https://physna-app.auth.us-east-2.amazoncognito.com/oauth2/token"

# List all environments
pcli2 env list

# Switch to an environment (with interactive selection)
pcli2 env use

# Or switch to an environment by name
pcli2 env use --name development

# Get details of the active environment
pcli2 env get

# Get details of a specific environment
pcli2 env get --name production

# Reset all environment configurations
pcli2 env reset

Each environment can have its own:

  • API base URL (for API calls)
  • UI base URL (for comparison viewer links)
  • Authentication URL (for OAuth2 token requests)

Choosing a Tenant

Most commands act on the active tenant. Pick it once; --tenant overrides it for a single command.

# List the tenants your credentials can reach
pcli2 tenant list

# Make one active, by short name or by UUID
pcli2 tenant use --name demo
pcli2 tenant use --name 123e4567-e89b-12d3-a456-426614174000

# Show the active tenant
pcli2 tenant get

# Clear it
pcli2 tenant clear

Next Steps

Getting Help

For help with any command, use the built-in help system:

# Install man pages for offline reference (man pcli2, man pcli2-asset-create, ...)
mkdir -p ~/.local/share/man/man1 && pcli2 man --output-dir ~/.local/share/man/man1

# General help
pcli2 --help

# Help for a specific command group
pcli2 asset --help

# Help for a specific command
pcli2 asset create --help

You can also use the -h or --help flag with any command to get detailed usage information.

Geometric Matching

PCLI2 provides powerful geometric matching capabilities to find similar assets in your Physna tenant. This feature leverages advanced algorithms to identify assets with similar geometries, regardless of their orientation, scale, or position.

Table of Contents

Overview

Geometric matching helps you:

  • Find duplicate or near-duplicate assets
  • Identify variations of the same part
  • Locate similar components across different projects
  • Reduce storage costs by identifying redundant assets
  • Improve design workflows by finding existing similar parts

Geometric matching serves as the foundation for other powerful capabilities:

  • Metadata Inference: Automatically propagate metadata from reference assets to geometrically similar assets using pcli2 asset metadata inference
  • Metadata Management: Create, update, retrieve, and delete metadata for assets using commands like pcli2 asset metadata create, pcli2 asset metadata get, and pcli2 asset metadata delete
  • Part Family Management: Organize and categorize groups of similar components
  • Design Optimization: Identify opportunities for part consolidation and standardization

Single Asset Matching

Find geometrically similar assets for a specific reference asset.

Basic Usage

# Find matches for a specific asset
pcli2 asset geometric-match --path /Home/Folder/ReferenceModel.stl --threshold 80.0

# Using asset UUID instead of path
pcli2 asset geometric-match --uuid 123e4567-e89b-12d3-a456-426614174000 --threshold 85.0

# Find matches with CSV output and headers
pcli2 asset geometric-match --path /Home/Folder/ReferenceModel.stl --threshold 80.0 --format csv --headers

# Find matches with CSV output, headers, and metadata
pcli2 asset geometric-match --path /Home/Folder/ReferenceModel.stl --threshold 80.0 --format csv --headers --metadata

Output Formats

JSON Format (Default)

[
  {
    "referenceAssetName": "ReferenceModel.stl",
    "candidateAssetName": "SimilarModel.stl",
    "matchPercentage": 95.75,
    "referenceAssetPath": "/Home/Folder/ReferenceModel.stl",
    "candidateAssetPath": "/Home/DifferentFolder/SimilarModel.stl",
    "referenceAssetUuid": "123e4567-e89b-12d3-a456-426614174000",
    "candidateAssetUuid": "987fc321-fedc-ba98-7654-43210fedcba9"
  }
]

CSV Format

REFERENCE_ASSET_NAME,CANDIDATE_ASSET_NAME,MATCH_PERCENTAGE,REFERENCE_ASSET_PATH,CANDIDATE_ASSET_PATH,REFERENCE_ASSET_UUID,CANDIDATE_ASSET_UUID,COMPARISON_URL
ReferenceModel.stl,SimilarModel.stl,95.75,/Home/Folder/ReferenceModel.stl,/Home/DifferentFolder/SimilarModel.stl,123e4567-e89b-12d3-a456-426614174000,987fc321-fedc-ba98-7654-43210fedcba9,https://app.physna.com/tenants/demo-1/compare?asset1Id=123e4567-e89b-12d3-a456-426614174000&asset2Id=987fc321-fedc-ba98-7654-43210fedcba9&tenant1Id=68555ebf-f09c-4861-96b1-692d2ec10de7&tenant2Id=68555ebf-f09c-4861-96b1-692d2ec10de7&searchType=geometric&matchPercentage=95.75

CSV Format with Metadata

When using the --metadata flag, the output includes metadata fields from both the reference and candidate assets. This produces CSV output with additional metadata columns prefixed with REF_ for reference asset metadata and CAN_ for candidate asset metadata. The output also includes a COMPARISON_URL column that provides a link to view the comparison in the Physna UI:

REFERENCE_ASSET_PATH,CANDIDATE_ASSET_PATH,MATCH_PERCENTAGE,REFERENCE_ASSET_UUID,CANDIDATE_ASSET_UUID,COMPARISON_URL,REF_MATERIAL,CAN_MATERIAL,REF_COLOR,CAN_COLOR
/Home/Folder/ReferenceModel.stl,/Home/DifferentFolder/SimilarModel.stl,95.75,123e4567-e89b-12d3-a456-426614174000,987fc321-fedc-ba98-7654-43210fedcba9,https://app.physna.com/tenants/demo-1/compare?asset1Id=123e4567-e89b-12d3-a456-426614174000&asset2Id=987fc321-fedc-ba98-7654-43210fedcba9&tenant1Id=68555ebf-f09c-4861-96b1-692d2ec10de7&tenant2Id=68555ebf-f09c-4861-96b1-692d2ec10de7&searchType=geometric&matchPercentage=95.75,Steel,Aluminum,Red,Blue

All metadata fields from all matched assets are included as columns, with empty values for assets that don't have a particular metadata field.

Complete Examples

Here are complete examples showing the command with and without the --metadata flag:

Without metadata:

pcli2 asset geometric-match --path /Home/Folder/ReferenceModel.stl --threshold 80.0 --format csv --headers

Output:

REFERENCE_ASSET_PATH,CANDIDATE_ASSET_PATH,MATCH_PERCENTAGE,REFERENCE_ASSET_UUID,CANDIDATE_ASSET_UUID,COMPARISON_URL
/Home/Folder/ReferenceModel.stl,/Home/DifferentFolder/SimilarModel.stl,95.75,123e4567-e89b-12d3-a456-426614174000,987fc321-fedc-ba98-7654-43210fedcba9,https://app.physna.com/tenants/demo-1/compare?asset1Id=123e4567-e89b-12d3-a456-426614174000&asset2Id=987fc321-fedc-ba98-7654-43210fedcba9&tenant1Id=68555ebf-f09c-4861-96b1-692d2ec10de7&tenant2Id=68555ebf-f09c-4861-96b1-692d2ec10de7&searchType=geometric&matchPercentage=95.75

With metadata:

pcli2 asset geometric-match --path /Home/Folder/ReferenceModel.stl --threshold 80.0 --format csv --headers --metadata

Output:

REFERENCE_ASSET_PATH,CANDIDATE_ASSET_PATH,MATCH_PERCENTAGE,REFERENCE_ASSET_UUID,CANDIDATE_ASSET_UUID,COMPARISON_URL,REF_MATERIAL,CAN_MATERIAL,REF_COLOR,CAN_COLOR
/Home/Folder/ReferenceModel.stl,/Home/DifferentFolder/SimilarModel.stl,95.75,123e4567-e89b-12d3-a456-426614174000,987fc321-fedc-ba98-7654-43210fedcba9,https://app.physna.com/tenants/demo-1/compare?asset1Id=123e4567-e89b-12d3-a456-426614174000&asset2Id=987fc321-fedc-ba98-7654-43210fedcba9&tenant1Id=68555ebf-f09c-4861-96b1-692d2ec10de7&tenant2Id=68555ebf-f09c-4861-96b1-692d2ec10de7&searchType=geometric&matchPercentage=95.75,Steel,Aluminum,Red,Blue

Threshold Settings

The threshold parameter controls the minimum similarity percentage required for a match:

  • 0.0 - Return all possible matches (may include unrelated assets)
  • 50.0 - Very loose matching (many potential matches)
  • 80.0 - Default setting (good balance of accuracy and recall)
  • 90.0 - Strict matching (high confidence matches)
  • 95.0+ - Very strict matching (near duplicates only)

Folder-Based Matching

Find geometrically similar assets for all assets in a specified folder. This command processes assets in parallel for improved performance.

Basic Usage

# Find matches for all assets in a folder
pcli2 folder geometric-match --folder-path /Home/SearchFolder/ --threshold 85.0

Including Subfolders

By default only the assets sitting directly in the named folder are matched. A folder that holds nothing but subfolders therefore produces no report:

# /Creo Files contains 8 subfolders and no assets of its own
pcli2 folder geometric-match --folder-path "/Creo Files" --threshold 85.0
# ❌ Error: No assets found directly in the specified folder(s)
#    1. The folder(s) contain 8 subfolder(s) - pass --recursive to include the assets in them

Pass --recursive (-R) to walk the whole subtree:

# Matches every asset under /Creo Files, including all of its subfolders
pcli2 folder geometric-match --folder-path "/Creo Files" --threshold 85.0 --recursive

--recursive can widen the scope dramatically — a folder with one asset of its own may have thousands underneath it, and each one costs a search. Raise --concurrent (up to 10) to speed it up, or name a deeper folder to narrow the scope.

The same flag is available on folder part-match and folder visual-match.

Comparison Viewer URL

Both geometric-match and folder geometric-match commands include a comparison URL in their output that allows you to view the geometric match in the Physna UI. The URL is available in both JSON and CSV formats:

  • JSON: The field is named comparisonUrl
  • CSV: The column is named COMPARISON_URL

The URL follows this format:

https://app.physna.com/tenants/{tenant_short_name}/compare?asset1Id={reference_asset_uuid}&asset2Id={candidate_asset_uuid}&tenant1Id={tenant_uuid}&tenant2Id={tenant_uuid}&searchType=geometric&matchPercentage={match_percentage}

Excel (XLSX) Output

In addition to json and csv, the folder match command supports --format xls, which writes a color-highlighted Excel workbook designed for a human reader. It contains exactly the same columns, in the same order, as the CSV output (always including the REF_/CAN_ metadata pairs), rendered with visual aids that make a large report easy to scan:

  • Frozen headers and identity columns — the two header rows and the leading reference path, candidate path, and match-percentage columns stay in view while you scroll a wide, tall report.
  • Grouped metadata pairs — each REF_<field>/CAN_<field> pair is boxed and labeled once with the field name (e.g. MATERIAL over a REF and a CAN sub-column), so the reference/candidate pairs stand out among the plain columns.
  • Metadata diff highlighting — for every pair, both cells are shaded: 🟩 green when the two values match, 🟥 red when they differ, and 🟨 amber when a value is present on only one side.
  • Match-score heat map — the MATCH_PERCENTAGE column is shaded on a gradient (cool at 0%, through yellow at 50%, to red-hot at 100%) and the rows are sorted by match percentage, highest first.
  • Clickable comparison linksCOMPARISON_URL is the last column (its long value is rarely read, so the metadata columns come before it), written as a hyperlink you can click to open the side-by-side comparison in a browser.

Because Excel is a binary format, xls writes to a file rather than standard output. Use --output (or -o) to choose the path; if omitted, the workbook is written to match_report.xlsx in the current directory. The extension is always normalized to .xlsx (the modern Office Open XML format); if it had to be changed, a warning is printed to stderr. On success the command follows the UNIX convention of printing nothing to stdout.

# Write a highlighted Excel report for a folder
pcli2 folder geometric-match --folder-path /Home/SearchFolder/ --threshold 80.0 --format xls --output report.xlsx

# Multiple folders, default output filename (match_report.xlsx)
pcli2 folder geometric-match --folder-path /Home/FolderA/ --folder-path /Home/FolderB/ --format xls

The xls format always includes metadata (the metadata diff is its whole point), so the --metadata flag is implied and does not need to be passed.

Performance Options

Concurrency Control

Control how many simultaneous operations are performed (range: 1-10, default: 1):

# Use 8 concurrent operations (default is 1, maximum is 10)
pcli2 folder geometric-match --folder-path /Home/SearchFolder/ --concurrent 8

# Use the default (1 concurrent operation)
pcli2 folder geometric-match --folder-path /Home/SearchFolder/

# Invalid values will cause the command to fail
pcli2 folder geometric-match --folder-path /Home/SearchFolder/ --concurrent 15
# This will show an error: "Invalid value for '--concurrent': must be between 1 and 10, got 15"

Progress Tracking

Display progress information during long-running operations:

# Show progress information
pcli2 folder geometric-match --folder-path /Home/SearchFolder/ --progress

# Combine with concurrency to show multiple progress bars (one per concurrent operation)
pcli2 folder geometric-match --folder-path /Home/SearchFolder/ --concurrent 8 --progress

When using both --concurrent and --progress flags together, the command will display:

  • An overall progress bar showing the total completion percentage
  • Individual progress bars for each concurrent operation showing which assets are being processed
  • Status messages indicating the current stage of each operation (starting search, processing matches, completion)

With --recursive, --progress also covers the folder scan that happens before any matching starts. A deep tree costs one API call per folder, so this phase can run for a while on its own:

⠹ Scanning /Creo Files: 46/312 folders, 1174 assets found

followed by a summary once the scan completes:

Scanned 1 folder path(s), found 3182 asset(s) to match

All of this goes to stderr, so piping stdout to a file or another command is unaffected. Without --progress the scan is silent.

Performance Options

Concurrency and Progress Combined

For optimal performance monitoring, combine both options:

# Use 10 concurrent operations with detailed progress tracking
pcli2 folder geometric-match --folder-path /Home/SearchFolder/ --concurrent 10 --progress

# Combine with other options
pcli2 folder geometric-match --folder-path /Home/SearchFolder/ --threshold 85.0 --concurrent 8 --progress

Resuming an Interrupted Run

A match over a large tenant can run for hours, and until the report is written nothing has been saved. --checkpoint FILE changes that: every asset's result is appended to FILE the moment its search finishes, and re-running the same command with the same file reuses what was recorded and searches only the assets that are left.

# First attempt - interrupted after two hours
pcli2 folder geometric-match --folder-path "/Creo Files" --recursive \
  --threshold 85 --concurrent 8 --progress \
  --checkpoint creo-match.jsonl --format csv --headers > creo-matches.csv

# Same command again: picks up where it stopped
pcli2 folder geometric-match --folder-path "/Creo Files" --recursive \
  --threshold 85 --concurrent 8 --progress \
  --checkpoint creo-match.jsonl --format csv --headers > creo-matches.csv

On the second run stderr reports what was reused:

Resuming from checkpoint 'creo-match.jsonl': 2,431 of 3,182 asset(s) already searched

Points worth knowing:

  • The file is tied to the exact run: search type, tenant, folder paths, --threshold, --recursive, --exclusive and (for visual search) --limit. A file written by a different combination is refused with a message naming the run it belongs to; delete it or pick another path.
  • Only successful searches are recorded. An asset whose search failed is searched again on the next run, which is also how a run that stopped on authentication failures is completed after pcli2 auth login.
  • The file is deleted once the report has been written successfully. It stays if the report fails - for example an Excel workbook too tall for a worksheet - so the same searches are not repeated after fixing the output options.
  • The output format is not part of the fingerprint: an interrupted CSV run can be finished as JSON or Excel.
  • Assets added to the folder between runs are searched; assets removed are dropped from the report.

part-match and visual-match take the same option.

Handling Large Folders

For folders with many assets, consider these strategies:

  1. Use a checkpoint: --checkpoint FILE makes an interruption cost minutes instead of hours
  2. Adjust threshold: Higher thresholds reduce processing time
  3. Increase concurrency: Use more concurrent operations (but watch resource usage)
  4. Process in batches: Break large folders into smaller subfolders

Direct Asset Similarity (Match Scores)

While geometric-match searches your tenant for assets similar to a single reference, asset similarity compares two specific assets and returns the pairwise match scores between them. Use it when you already know both assets you want to compare.

Each asset can be identified by either its UUID or its path — PCLI2 resolves paths to UUIDs automatically:

  • Reference (source) asset: --reference-uuid or --reference-path
  • Candidate (target) asset: --candidate-uuid or --candidate-path

Both assets must be 3D models in a finished state, and they must be different assets (comparing an asset with itself is rejected by the API).

Basic Usage

# Compare two assets by path
pcli2 asset similarity \
  --reference-path /Home/Folder/block1.stl \
  --candidate-path /Home/Folder/block2.stl

# Mix identifiers: reference by UUID, candidate by path
pcli2 asset similarity \
  --reference-uuid 123e4567-e89b-12d3-a456-426614174000 \
  --candidate-path /Home/Folder/block2.stl

# CSV output with headers
pcli2 asset similarity \
  --reference-path /Home/Folder/block1.stl \
  --candidate-path /Home/Folder/block2.stl \
  --format csv --headers

The command is also available under the alias pcli2 asset match-scores.

Output Formats

JSON Format (Default)

{
  "referenceAssetPath": "/Home/Folder/block1.stl",
  "referenceAssetUuid": "123e4567-e89b-12d3-a456-426614174000",
  "candidateAssetPath": "/Home/Folder/block2.stl",
  "candidateAssetUuid": "987fc321-fedc-ba98-7654-43210fedcba9",
  "geometric": {
    "matchPercentage": 90.21,
    "forwardMatchPercentage": 86.58,
    "reverseMatchPercentage": 86.58
  },
  "comparisonUrl": "https://app.physna.com/tenants/demo-1/compare?asset1Id=123e4567-e89b-12d3-a456-426614174000&asset2Id=987fc321-fedc-ba98-7654-43210fedcba9&tenant1Id=tenant-uuid&tenant2Id=tenant-uuid&searchType=geometric&matchPercentage=90.21"
}

The geometric scores describe how similar the two models are:

  • matchPercentage: Overall geometric similarity (100% = geometrically identical)
  • forwardMatchPercentage: How much of the reference asset's geometry exists in the candidate
  • reverseMatchPercentage: How much of the candidate asset's geometry exists in the reference

A volumetric object (with its own matchPercentage) is included only when volumetric scoring is enabled for your tenant; otherwise it is omitted. Contact Physna sales to enable volumetric scoring.

CSV Format

REFERENCE_ASSET_PATH,CANDIDATE_ASSET_PATH,MATCH_PERCENTAGE,FORWARD_MATCH_PERCENTAGE,REVERSE_MATCH_PERCENTAGE,VOLUMETRIC_MATCH_PERCENTAGE,REFERENCE_ASSET_UUID,CANDIDATE_ASSET_UUID,COMPARISON_URL
/Home/Folder/block1.stl,/Home/Folder/block2.stl,90.21,86.58,86.58,,123e4567-e89b-12d3-a456-426614174000,987fc321-fedc-ba98-7654-43210fedcba9,https://app.physna.com/tenants/demo-1/compare?asset1Id=123e4567-e89b-12d3-a456-426614174000&asset2Id=987fc321-fedc-ba98-7654-43210fedcba9&tenant1Id=tenant-uuid&tenant2Id=tenant-uuid&searchType=geometric&matchPercentage=90.21

The VOLUMETRIC_MATCH_PERCENTAGE column is empty unless volumetric scoring is enabled for your tenant.

Error Handling

Common Errors

HTTP 409 Conflict

A 409 from the search endpoint means the asset cannot be searched in its current state: it is still indexing, has no 3D data, or failed to index. This is a property of the tenant, not of the run, so the asset is counted as "not searchable" in the summary and the run continues; it is not retried. Transient failures (connection errors, 408/429/502/503/504) are retried with backoff, and a 401/403 triggers one token renewal and retry. A run that loses more than 10% of its searches to operational failures, or that is stopped by repeated authentication failures, exits 69 rather than producing a report that looks complete.

Permission Denied

When you don't have permission to perform geometric search:

ERROR: Error: Access forbidden. You don't have permission to perform geometric search on this asset.

Check your tenant permissions and API credentials.

Asset Not Found

When the specified asset or folder cannot be found:

ERROR: The asset with ID 'XXX' cannot be found in tenant 'YYY'

Verify the asset path or UUID is correct.

Best Practices

Optimizing Performance

  1. Use appropriate thresholds: Start with 80-85% and adjust based on results
  2. Limit search scope: Use specific folders rather than searching entire tenants
  3. Monitor resource usage: Adjust concurrency based on your system capabilities
  4. Use progress tracking: Monitor long-running operations

Interpreting Results

  • High match percentages (>95%): Likely duplicates or very similar assets
  • Medium match percentages (80-95%): Similar geometry with variations
  • Low match percentages (<80%): May be false positives or loosely related

Automation Tips

  1. Schedule regular deduplication: Run geometric matching periodically to identify duplicates
  2. Integrate with CI/CD: Use geometric matching in automated workflows
  3. Export results: Use CSV format for easy analysis in spreadsheets

Advanced Usage

Scripting Examples

Bash Script for Regular Deduplication

#!/bin/bash
# deduplicate.sh

FOLDERS=("/Home/ProjectA/" "/Home/ProjectB/" "/Home/Archive/")
THRESHOLD=95.0
CONCURRENT=8  # Number of concurrent operations
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

for folder in "${FOLDERS[@]}"; do
    echo "Processing folder: $folder"
    pcli2 folder geometric-match \
        --folder-path "$folder" \
        --threshold $THRESHOLD \
        --concurrent $CONCURRENT \
        --format csv \
        --progress \
        > "duplicates_${folder//\//_}_$TIMESTAMP.csv"
done

echo "Deduplication complete. Results saved to CSV files."

PowerShell Script for Windows

# deduplicate.ps1

$Folders = @("/Home/ProjectA/", "/Home/ProjectB/", "/Home/Archive/")
$Threshold = 95.0
$Concurrent = 8  # Number of concurrent operations
$Timestamp = Get-Date -Format "yyyyMMdd_HHmmss"

foreach ($folder in $Folders) {
    Write-Host "Processing folder: $folder"
    pcli2 folder geometric-match `
        --folder-path $folder `
        --threshold $Threshold `
        --concurrent $Concurrent `
        --format csv `
        --progress `
        > "duplicates_$($folder.Replace('/', '_'))_$Timestamp.csv"
}

Write-Host "Deduplication complete. Results saved to CSV files."

Troubleshooting

Performance Issues

If matching operations are taking too long:

  1. Reduce concurrency: Lower the --concurrent value
  2. Increase threshold: Use higher threshold values to reduce matches
  3. Check network: Ensure good connectivity to the Physna API
  4. Monitor server status: Check if the Physna service is experiencing issues

Incomplete Results

If you're not seeing expected matches:

  1. Lower threshold: Try lower threshold values
  2. Check asset types: Ensure assets are compatible geometric file types
  3. Verify permissions: Confirm you have access to all assets in the search scope
  4. Contact support: If issues persist, reach out to Physna support
  • asset geometric-match - Find matches for a single asset
  • folder geometric-match - Find matches for all assets in a folder
  • asset similarity - Get pairwise match scores between two specific assets (alias: asset match-scores)
  • asset list - List assets in a folder
  • asset get - Get detailed asset information

Use pcli2 asset geometric-match --help, pcli2 folder geometric-match --help, and pcli2 asset similarity --help for detailed command information.

Metadata Operations

PCLI2 provides comprehensive metadata operations for managing asset metadata including creating, retrieving, updating, and deleting asset metadata.

Overview

Metadata is essential for organizing and searching your assets effectively. PCLI2 supports comprehensive metadata operations to help you manage your asset metadata efficiently.

Metadata Operations

PCLI2 provides several commands for working with asset metadata:

1. Create/Update Individual Asset Metadata

Add or update a single metadata field on an asset:

# Add or update a single metadata field on an asset
pcli2 asset metadata create --path "/Home/Folder/Model.stl" --name "Material" --value "Steel" --type "text"

# Add or update a single metadata field on an asset by UUID
pcli2 asset metadata create --uuid "123e4567-e89b-12d3-a456-426614174000" --name "Weight" --value "15.5" --type "number"

2. Retrieve Asset Metadata

Get all metadata for an asset:

# Get all metadata for an asset in JSON format (default)
pcli2 asset metadata get --path "/Home/Folder/Model.stl"

# Get all metadata for an asset in CSV format (suitable for batch operations)
pcli2 asset metadata get --uuid "123e4567-e89b-12d3-a456-426614174000" --format csv

3. Delete Asset Metadata

Delete specific metadata fields from an asset:

# Delete specific metadata fields from an asset
pcli2 asset metadata delete --path "/Home/Folder/Model.stl" --name "Material" --name "Weight"

# Delete metadata fields using comma-separated list
pcli2 asset metadata delete --uuid "123e4567-e89b-12d3-a456-426614174000" --name "Material,Weight,Description"

The delete command now uses the dedicated API endpoint to properly remove metadata fields from assets, rather than fetching all metadata and re-updating the asset without the specified fields. This provides more efficient and accurate metadata deletion.

4. Create/Update Metadata for Multiple Assets

Create or update metadata for multiple assets from a CSV file:

# Create or update metadata for multiple assets from a CSV file
pcli2 asset metadata create-batch --input "metadata.csv"

CSV Formats for Batch Metadata Operations

The create-batch command accepts two CSV layouts. The layout is detected automatically from the header row: if any column name starts with metadata:, the file is treated as the UI (horizontal) format; otherwise it is treated as the classic (vertical) format. You can also force a layout explicitly with --csv-format classic or --csv-format ui (the default is --csv-format auto).

In both layouts, empty values are skipped by default: the existing metadata field on the asset, if any, is left untouched, so a sparse file can be used to incrementally add or update fields. Pass --delete-if-empty to instead delete a metadata field from the asset when the file contains an empty value for it — useful when replacing an asset's metadata wholesale.

Classic (Vertical) Format

The classic CSV format used by asset metadata get --format csv and asset metadata create-batch --input is designed for seamless round-trip operations:

ASSET_PATH,NAME,VALUE,TYPE
/Home/Folder/Model1.stl,Material,Steel,text
/Home/Folder/Model1.stl,Weight,15.5,number
/Home/Folder/Model2.ipt,Inventory Qty,42,number
/Home/Folder/Model2.ipt,Supplier Link,https://example.com/,url
/Home/Folder/Model2.ipt,Exportable,true,boolean

The CSV format specifications:

  • Header Row: Must contain ASSET_PATH,NAME,VALUE in that order, optionally followed by TYPE
  • ASSET_PATH: Path to the asset in Physna (e.g., /Home/Folder/Model.stl). A leading /Home — the name Physna shows for the root folder — is treated as the root, so /Home/NX/part.prt, /NX/part.prt, and NX/part.prt all refer to the same asset
  • NAME: Name of the metadata field to set
  • VALUE: Value to assign to the metadata field. Values are automatically coerced to the field's type (see Metadata Field Types). An empty value is skipped by default, or deletes the field from the asset when --delete-if-empty is passed
  • TYPE (optional): One of text (default), number, boolean, or url. This only governs the type used when registering a new field; for a field that already exists in Physna, the existing registered type is authoritative and the TYPE column is ignored. The column is optional per row — some rows may include it and others may omit it
  • File Encoding: Must be UTF-8 encoded
  • Quoting: Values containing commas, quotes, or newlines must be enclosed in double quotes
  • Escaping: Double quotes within values must be escaped by doubling them (e.g., "15.5"" diameter")
  • Empty Rows: Will be ignored during processing
  • Multiple Fields: If an asset has multiple metadata fields to update, include multiple rows with the same ASSET_PATH but different NAME and VALUE combinations

Example Command:

# Create/update metadata for multiple assets from a CSV file
pcli2 asset metadata create-batch --input "metadata.csv"

Deleting metadata fields via CSV:

Pass --delete-if-empty and leave the VALUE column empty to remove a metadata field from an asset:

ASSET_PATH,NAME,VALUE
/Home/Folder/Model1.stl,ObsoleteField,
/Home/Folder/Model1.stl,Material,Steel
pcli2 asset metadata create-batch --input "metadata.csv" --delete-if-empty

In the example above, ObsoleteField is deleted and Material is set to Steel in a single pass. Without --delete-if-empty, the ObsoleteField row would be skipped with a warning and only Material would be updated.

Note: The create-batch command groups all rows by asset path, then issues deletes (empty values, when --delete-if-empty is passed) followed by updates (non-empty values) per asset in one batch. Multiple rows with the same ASSET_PATH are combined into a single API interaction.

UI (Horizontal) Format

The Physna web UI's bulk metadata upload uses a horizontal layout with one row per asset and one column per metadata field. create-batch accepts these files directly:

"path","id","metadata:Material","metadata:Color","metadata:Weight"
"/domain/assets/part1.sldprt","123e4567-e89b-12d3-a456-426614174000","Steel","Blue","2.5kg"
"/domain/assets/part2.step","","Aluminum","Red","1.2kg"
"/domain/assets/assembly.sldasm","","Mixed","",""

The UI format specifications:

  • path: Full path to the asset in Physna
  • id: Optional asset UUID. When present and non-empty, it takes precedence over the path and is used directly, without path resolution. An invalid UUID is an error (there is no fallback to the path, since that could silently target a different asset)
  • metadata:<field name>: One column per metadata field. The metadata: prefix is stripped to obtain the field name
  • Empty metadata cells: Skipped by default — the existing field value on the asset, if any, is left untouched. With --delete-if-empty, an empty cell deletes the field from the asset instead
  • Other columns: Any column that is not path, id, or metadata:* is ignored, with a warning listing the ignored columns
  • Row identification: Each row must provide a UUID or a path; a row with neither is an error

The whole file is parsed and validated before any API call is made, so a malformed file (e.g. an invalid UUID) fails fast with a line-numbered error instead of half-applying.

# Auto-detected from the header row
pcli2 asset metadata create-batch --input "ui-export.csv"

# Or forced explicitly
pcli2 asset metadata create-batch --input "ui-export.csv" --csv-format ui

Listing a Tenant's Registered Metadata Fields

Metadata fields are registered per tenant, each with a name and a type. Use tenant metadata list to see every field currently registered in the active tenant:

# JSON (default)
pcli2 tenant metadata list

# CSV, ready to turn into a create-batch file
pcli2 tenant metadata list --format csv --headers

The CSV output uses the same column headers as the classic create-batch input (ASSET_PATH,NAME,VALUE,TYPE), with NAME and TYPE filled from the registry and ASSET_PATH and VALUE left blank:

ASSET_PATH,NAME,VALUE,TYPE
,Description,,text
,Exportable,,boolean
,Inventory Qty,,number
,Supplier Link,,url
,Unit Price ($),,number

This makes it easy to build a batch-upload template: save the listing, then for each asset fill in ASSET_PATH and VALUE (replicating the field rows per asset). Because values are coerced to each field's registered type, you do not need to touch the TYPE column for fields that already exist.

# Save the field list as a starting template
pcli2 tenant metadata list --format csv --headers > fields.csv

Advanced Metadata Workflow: Export, Modify, Reimport

One of the most powerful features of PCLI2 is the ability to export metadata, modify it externally, and reimport it:

  1. Export Metadata:

    # Export all metadata for an asset to a CSV file
    pcli2 asset metadata get --path "/Home/Folder/Model.stl" --format csv > model_metadata.csv
    
    # Export metadata for multiple assets in a folder
    pcli2 asset list --folder-path "/Home/Folder/" --metadata --format csv > folder_metadata.csv
    
  2. Modify Metadata Externally:

    • Open the CSV file in a spreadsheet application (Excel, Google Sheets, etc.)
    • Make the desired changes to metadata values
    • To delete a field, clear its VALUE cell (leave it blank) and reimport with --delete-if-empty
    • Save the file in CSV format
  3. Reimport Modified Metadata:

    # Update assets with modified metadata (blank values are skipped)
    pcli2 asset metadata create-batch --input "modified_metadata.csv"
    
    # Or replace metadata wholesale: blank values delete the field from the asset
    pcli2 asset metadata create-batch --input "modified_metadata.csv" --delete-if-empty
    

This workflow enables powerful bulk metadata operations while maintaining the flexibility to use familiar spreadsheet tools for data manipulation.

Metadata Field Types

PCLI2 supports four metadata field types:

  1. Text (default): String values

    pcli2 asset metadata create --path "/Home/Model.stl" --name "Description" --value "Sample part description" --type "text"
    
  2. Number: Numeric values

    pcli2 asset metadata create --path "/Home/Model.stl" --name "Weight" --value "15.5" --type "number"
    
  3. Boolean: True/False values

    pcli2 asset metadata create --path "/Home/Model.stl" --name "Approved" --value "true" --type "boolean"
    
  4. URL: Link values (stored as a string)

    pcli2 asset metadata create --path "/Home/Model.stl" --name "Supplier Link" --value "https://example.com/" --type "url"
    

Automatic type coercion

Every metadata field in a tenant is registered with a type, and the Physna API rejects a value whose JSON type does not match. Because a CSV cell is just text, PCLI2 coerces each value to the field's registered type before sending it — so create-batch works against typed fields without you having to declare anything:

  • A number field receives 18 (a JSON number) rather than the string "18"; 84.50 is sent as 84.5
  • A boolean field accepts true/false, 1/0, yes/no, on/off (case-insensitive)
  • text and url fields store the value as a string

If a value cannot be represented as the field's type — for example the text N/A for a number field — that row is a type conflict and is reported as an error (see create-batch Error Behavior).

The registered type always wins. The --type flag (single create) and the TYPE column (batch) only decide the type used when a field is registered for the first time; they cannot change the type of an existing field. To change a field's type, delete and recreate it.

Best Practices

  1. Use Descriptive Names: Choose clear, consistent names for metadata fields across your organization
  2. Validate Data Types: Ensure values match the expected data type for each field
  3. Batch Operations: Use CSV batch operations for large-scale metadata updates
  4. Backup Before Bulk Operations: Export metadata before performing bulk deletions
  5. Test First: Use small test sets before applying operations to large asset collections
  6. Use Proper Authentication: Ensure your credentials have appropriate permissions for metadata operations

Error Handling

Metadata operations provide detailed error messages, retry transient network failures internally, and validate input formats before processing.

create-batch Error Behavior

By default, asset metadata create-batch stops on the first error and prints a summary of how many assets were processed successfully. This makes failures visible instead of letting a batch silently complete with partial results.

Specifically:

  • CSV parsing errors: always terminate immediately — the input file is expected to be well-formed
  • Unresolvable asset paths (asset not found): by default, terminates the batch. Pass --continue-on-error to skip the failing asset and continue with the remaining rows
  • Metadata update/delete failures, including type conflicts (a value that cannot be represented as the field's registered type): by default, terminate the batch. Pass --continue-on-error to skip the offending asset and continue with the remaining rows
  • Authentication failures: always terminate with a remediation message directing the user to re-authenticate, regardless of --continue-on-error

With --continue-on-error, skipped assets are reported with a concise warning as they are encountered, and the final summary reports how many assets succeeded and how many failed.

Example — skip both unresolvable paths and conflicting values:

pcli2 asset metadata create-batch --input "metadata.csv" --continue-on-error

On completion (or termination), a summary is printed to stderr showing the number of successful and failed assets.

Performance Considerations

Large-Scale Operations

For bulk metadata operations:

# Process during off-peak hours
pcli2 asset metadata create-batch --input "large_metadata.csv"

Monitoring Progress

Monitor progress during long-running operations:

# Show progress during batch operations
pcli2 asset metadata create-batch --input "metadata.csv" --progress

Integration with Other Commands

Metadata operations work seamlessly with other PCLI2 commands:

# Chain with asset operations
pcli2 asset list --folder-path "/Home/Parts/" --format csv | \
pcli2 asset metadata create-batch --input "metadata_updates.csv"

# Export results for auditing
pcli2 asset metadata get --path "/Home/Parts/Model.stl" --format csv > metadata_export.csv

Limitations

  1. API Rate Limits: Extensive operations may be rate-limited by the Physna API
  2. Processing Time: Large batch operations can take considerable time
  3. Metadata Types: Supports text, number, boolean, and url metadata fields
  4. Asset Access: Can only process assets accessible to your authenticated user
  5. Field Names: Metadata field names must be unique per asset and follow Physna naming conventions

Always test operations on a small scale before running them on large datasets.

Metadata Inference

The metadata inference feature allows you to automatically apply metadata from a reference asset to geometrically similar assets, significantly reducing manual metadata entry work.

Overview

Metadata inference works by:

  1. Taking a reference asset and specified metadata fields
  2. Finding geometrically similar assets using the Physna geometric search
  3. Applying the reference metadata to matching assets

This is particularly useful for applying common metadata like materials, categories, suppliers, or costs to families of similar parts.

Basic Usage

Apply metadata from a reference asset to similar assets:

pcli2 asset metadata inference --path /Home/Parts/Bolt-M8x20.stl --name "Material" --threshold 90.0

This command will:

  • Find the asset at /Home/Parts/Bolt-M8x20.stl
  • Extract the "Material" metadata field value
  • Find all assets with 90% or higher geometric similarity
  • Apply the same "Material" value to all matching assets

Specifying Multiple Metadata Fields

You can apply multiple metadata fields in a single operation:

# Using comma-separated values
pcli2 asset metadata inference --path /Home/Parts/BaseModel.stl --name "Material,Cost,Supplier" --threshold 85.0

# Using multiple --name flags
pcli2 asset metadata inference --path /Home/Parts/BaseModel.stl --name "Material" --name "Cost" --name "Supplier" --threshold 85.0

Threshold Values

The threshold parameter controls the similarity requirement for matching assets:

  • Range: 0.00 to 100.00
  • Higher values: More stringent matching (fewer but more similar matches)
  • Lower values: More permissive matching (more but less similar matches)
  • Recommended starting point: 80.00-85.00 for most use cases
# Very strict matching (high similarity required)
pcli2 asset metadata inference --path /Home/Parts/Reference.stl --name "CriticalField" --threshold 95.0

# Liberal matching (find more potential matches)
pcli2 asset metadata inference --path /Home/Parts/Reference.stl --name "GeneralField" --threshold 75.0

Practical Examples

Applying Standard Materials

# Apply standard material to a family of similar bolts
pcli2 asset metadata inference --path /Home/StandardParts/Bolt-M8x20.stl --name "Material" --threshold 92.0

Categorizing Product Lines

# Assign category and supplier information to a product family
pcli2 asset metadata inference --path /Home/ProductLine/MainAssembly.stl --name "Category,Supplier,Division" --threshold 85.0

Cost Propagation

# Apply estimated costs to similar components
pcli2 asset metadata inference --path /Home/Components/ReferenceBracket.stl --name "EstimatedCost,Currency" --threshold 88.0

Best Practices

1. Start with Conservative Thresholds

Begin with higher threshold values (85-90%) to ensure high-quality matches, then adjust based on results:

pcli2 asset metadata inference --path /Home/Parts/Reference.stl --name "Material" --threshold 90.0

2. Test with Non-Critical Metadata

Start by applying metadata to non-critical fields to understand the matching behavior:

pcli2 asset metadata inference --path /Home/Test/Reference.stl --name "TestTag" --threshold 85.0

3. Combine with Geometric Matching

Use geometric matching first to preview results, then apply metadata inference:

# Preview matches
pcli2 asset geometric-match --path /Home/Parts/Reference.stl --threshold 85.0 --format csv

# Apply metadata if preview looks good
pcli2 asset metadata inference --path /Home/Parts/Reference.stl --name "Material" --threshold 85.0

Error Handling

The metadata inference command is designed to be resilient:

  • Continues processing even if individual asset operations fail
  • Provides detailed error messages for troubleshooting
  • Automatically skips inaccessible assets

Common error scenarios and their handling:

  • Missing reference asset: Command aborts with clear error message
  • Network failures: Individual operations retry, overall process continues
  • Permission issues: Skips problematic assets with warning messages
  • Invalid metadata: Logs error but continues processing other assets

Performance Considerations

Large-Scale Operations

For bulk metadata inference operations:

# Process during off-peak hours
pcli2 asset metadata inference --path /Home/LargeAssembly/Reference.stl --name "Category" --threshold 80.0

Monitoring Progress

Monitor progress during long-running operations using the available flags:

pcli2 asset metadata inference --path /Home/Parts/Reference.stl --name "Material" --threshold 85.0

Integration with Other Commands

Metadata inference works seamlessly with other PCLI2 commands:

# Chain with folder operations
pcli2 folder list --folder-path /Home/ProductLine/ | \
pcli2 asset metadata inference --name "ProductLine" --threshold 85.0

# Export results for auditing
pcli2 asset metadata inference --path /Home/Parts/Reference.stl --name "Category" --threshold 85.0 \
  --format csv > metadata_propagation_log.csv

Limitations

  1. API Rate Limits: Large operations may be rate-limited by the Physna API
  2. Processing Time: Large operations can take considerable time
  3. Metadata Types: Only supports text, number, and boolean metadata fields
  4. Asset Access: Can only process assets accessible to your authenticated user

Always test operations on a small scale before running them on large datasets.

Scripting and Automation

PCLI2 is designed to work well in shell scripts, cron jobs, and CI/CD pipelines. This page collects the features that matter when no human is watching the terminal.

Table of Contents

Machine-Friendly Output

Colors, spinners, and progress bars are shown only when the output is a terminal. When you pipe or redirect output, you get clean text automatically:

# Clean JSON, no ANSI escape codes
pcli2 asset list --folder-path "/Home/Models/" --format json | jq '.[].name'

# CSV with headers for spreadsheets
pcli2 asset list --folder-path "/Home/Models/" --format csv --headers > assets.csv

To disable colors explicitly, use the --no-color flag or set the NO_COLOR (or PCLI2_NO_COLOR) environment variable.

The same rules apply to diagnostics on stderr: warnings and --verbose logs captured with 2> warnings.log are plain text with no ANSI escape codes, so they can be grepped and parsed directly.

Safe CSV for Spreadsheets

A CSV cell that starts with =, +, - or @ is evaluated as a formula by Excel, LibreOffice and Google Sheets when the file is opened, and asset names and metadata values come from whoever uploaded them. With --safe-csv (or PCLI2_SAFE_CSV=1) such cells are written with a leading single quote, which spreadsheets show as plain text. Values that are numbers, such as -5, are left alone. The default is off because the quote is visible to every other consumer of the file.

pcli2 asset list --folder-path "/Home/Parts" --format csv --headers --safe-csv > parts.csv

Excel workbooks written with --format xls are not affected: their cells are stored as strings and are never evaluated.

Machine-Readable Errors

With --error-format json (or PCLI2_ERROR_FORMAT=json) everything pcli2 writes to stderr is one JSON object per line: errors, their hints, warnings, --verbose log lines and the --stats summary. The last object of a failed run carries the exit code and its class:

$ pcli2 --error-format json asset delete --path /Home/Parts/nope.stl
{"level":"ERROR","code":67,"kind":"not_found","message":"API error: Path not found: /Home/Parts/nope.stl"}
$ echo $?
67
FieldMeaning
levelERROR, WARN, INFO or DEBUG, matching the log lines
codeThe process exit code, on the final error object
kindThe failure class: usage, data, no_input, not_found, unavailable, temp_fail, software, os, config, auth, network, api
messageThe same text the human-readable error would show
hintWhat to do about it, when pcli2 knows
http_statusThe HTTP status behind an API error, when there is one
stepsRemediation steps, on errors that list them

Progress bars and the upload/download statistics reports are not JSON; leave --progress off in scripts that parse stderr.

# Read the exit code and message of a failed run
if ! out=$(pcli2 --error-format json asset list --folder-path "/Nope" 2>&1 >/dev/null); then
  echo "$out" | tail -n 1 | jq -r '"\(.kind): \(.message)"'
fi

Skipping Prompts

Destructive commands ask for confirmation when run interactively. In scripts, pass --yes:

pcli2 folder delete --folder-path "/Home/Scratch/" --force --yes
pcli2 cache clear --yes

A prompt that cannot be shown is refused rather than answered for you: when stdin is not a terminal, or --no-input (or PCLI2_NO_INPUT=1) is set, a command that would have to ask exits 64 and says which flag to pass instead. tenant use and env use without --name fail the same way instead of showing a menu nobody can answer. Set PCLI2_NO_INPUT=1 in CI so a forgotten --yes fails fast rather than hanging on a prompt.

Authentication credentials can be passed as flags for non-interactive use:

pcli2 auth login --client-id "$PHYSNA_CLIENT_ID" --client-secret "$PHYSNA_CLIENT_SECRET"

Dry Run Mode

Preview destructive or bulk operations without changing anything on the server. Supported by asset delete, folder delete, asset create, asset create-batch, and folder upload:

# List exactly which files a batch upload would send, and where
pcli2 asset create-batch --input "build/*.stl" --folder-path "/Home/CI Builds/" --dry-run

# Confirm what a forced folder delete would remove
pcli2 folder delete --folder-path "/Home/Old Projects/" --force --dry-run

Exit Codes

PCLI2 uses distinct exit codes (following BSD sysexits.h conventions where possible) so scripts can react to specific failure classes:

CodeMeaning
0Success
64Command line usage error
65Data format error
66Cannot open input file
67Resource not found
69Temporary failure
70Internal software error
71Operating system error
78Configuration error
100Authentication error
101Network communication error
102Remote API error

A usage error rejected by the argument parser also exits 64. Batch commands that finished with some items failed, and folder matches whose report would be incomplete, exit 69.

pcli2 asset get --path "/Home/Models/part.stl" --format json
case $? in
  0)   echo "found" ;;
  100) pcli2 auth login ;;
  101) echo "network problem, try again later" ;;
  *)   echo "failed" ;;
esac

Verbosity Control

The global --quiet flag limits diagnostics to errors; --verbose (-v) enables debug-level logging. Both work on every command and take precedence over the PCLI2_LOG_LEVEL and RUST_LOG environment variables:

pcli2 --quiet asset create-batch --input "build/*.stl" --folder-path "/Home/CI Builds/"
PCLI2_LOG_LEVEL=trace pcli2 folder list

Automatic Retries

Transient failures (network timeouts, connection errors, and HTTP 408/429/502/503/504 responses) are retried automatically with exponential backoff, honoring the server's Retry-After header. The default is 2 retries; tune it with PCLI2_MAX_RETRIES (0 disables retries):

PCLI2_MAX_RETRIES=5 pcli2 folder download --folder-path "/Home/Models/" --output ./downloads

The request timeout defaults to 30 minutes (large model files take that long to transfer). Lower it with PCLI2_TIMEOUT (seconds) if you prefer fast failures over patience:

PCLI2_TIMEOUT=120 pcli2 asset list --folder-path "/Home/Models/"

Note that timeouts abort-and-retry only read requests (GETs); a timed-out write is never retried automatically because the server may have already processed it.

Resuming Interrupted Runs

Long runs in a script should be written so that a retry does not redo finished work:

# Downloads skip files already on disk
pcli2 folder download --folder-path "/Home/Parts" --output ./parts --resume

# Uploads skip files whose name is already in the folder
pcli2 asset create-batch --input "parts/*.stl" --folder-path "/Home/Parts" --skip-existing

# Folder matches record each completed search; the same command continues the run
pcli2 folder geometric-match --folder-path "/Home/Parts" --recursive \
  --checkpoint parts.jsonl --format csv --headers > parts.csv

The checkpoint file is removed when the report is written, so a loop that retries until the command exits 0 needs no cleanup of its own.

Request Statistics

Add --stats to any command to get one line on stderr at exit with the number of API requests made, how many were retried, how many token renewals happened, and the elapsed time. It is the quickest way to see whether a batch is doing more work than it should:

pcli2 --stats asset metadata create-batch --input metadata.csv
# 📊 5,102 API request(s), 2 retried, 1 token renewal(s) in 3m41s

Checking the Setup

pcli2 doctor prints the local state in one screen (binary and PATH, configuration, environment, credentials, token expiry, tenant, caches, API and auth-server reachability, update state) and exits non-zero when something is wrong: 78 for a local problem, 68 when a server cannot be reached. --format json makes it machine-readable.

Update Notifications

In interactive terminal sessions, PCLI2 prints a one-line hint on stderr when a newer release is available (checked at most once per day). The check never runs in CI (detected via the CI environment variable) or when output is redirected. To opt out entirely:

export PCLI2_NO_UPDATE_CHECK=1

CI/CD Example

A GitHub Actions job that uploads build artifacts to Physna:

jobs:
  upload-models:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install pcli2
        run: curl --proto '=https' --tlsv1.2 -LsSf https://github.com/jchultarsky101/pcli2/releases/latest/download/pcli2-installer.sh | sh
      - name: Authenticate
        run: pcli2 auth login --client-id "${{ secrets.PHYSNA_CLIENT_ID }}" --client-secret "${{ secrets.PHYSNA_CLIENT_SECRET }}"
      - name: Upload models
        run: |
          pcli2 tenant use --name my-tenant
          pcli2 asset create-batch --input "build/*.stl" \
            --folder-path "/Home/CI Builds/" --quiet --format json

Cross-Platform Configuration

PCLI2 reads a small set of environment variables. They are useful for WSL users running a Windows executable, for CI jobs, and for anyone who wants configuration and cache files somewhere other than the platform defaults.

# Where config.yml and the credentials file live
export PCLI2_CONFIG_DIR="/custom/path/to/config"

# Where the folder, tenant and metadata caches live
export PCLI2_CACHE_DIR="/custom/path/to/cache"

# Useful for WSL users running Windows executables
export PCLI2_CONFIG_DIR="/home/$USER/.pcli2"
export PCLI2_CACHE_DIR="/home/$USER/.pcli2/cache"
VariableEffect
PCLI2_CONFIG_DIRDirectory holding config.yml and dev_credentials.json. Default: the platform configuration directory (pcli2 config get path prints it).
PCLI2_CACHE_DIRDirectory for all cache files. Default: the platform cache directory.
PCLI2_FORMATDefault --format when the flag is not given on the command line.
PCLI2_HEADERSDefault --headers when the flag is not given (1/0, yes/no).
PCLI2_LOG_LEVELLog level: error, warn (default), info, debug, trace. RUST_LOG takes precedence when set.
PCLI2_TIMEOUTTotal request timeout in seconds (default 1800, to allow very large transfers). Connections time out after 15 seconds and a read after 300 seconds of silence regardless.
PCLI2_MAX_RETRIESRetries for transient failures: connection errors, 408/429/502/503/504 (default 2; 0 disables).
PCLI2_NO_COLOR, NO_COLORDisable colored output. PCLI2_NO_COLOR follows the pcli2 boolean rule (empty, 0, false, no, off mean off, anything else on); NO_COLOR disables when set to anything non-empty, per no-color.org.
PCLI2_SAFE_CSVGuard CSV output against spreadsheet formula injection. Same as --safe-csv.
PCLI2_NO_INPUTNever prompt; a command that would need an answer exits 64 instead. Same as --no-input.
PCLI2_ERROR_FORMATtext (default) or json. With json, every error, hint and log line on stderr is one JSON object; the last one carries the exit code. Same as --error-format.
PCLI2_NO_UPDATE_CHECK, CIDisable the once-a-day new-version hint.

API, UI and authentication URLs are not read from the environment. They belong to an environment definition: pcli2 env add --name staging --api-url ..., then pcli2 env use --name staging.

Paths are the same on every platform: /Home/Parts/Bracket.stl, where /Home (the name Physna shows for the root folder) is optional. Folder path matching is case-insensitive.

Documentation Deployment Instructions

GitHub Pages Setup

To deploy the Oranda-generated documentation to GitHub Pages, follow these steps:

  1. Enable GitHub Pages:

    • Go to your repository settings: https://github.com/jchultarsky101/pcli2/settings
    • Scroll down to the "Pages" section
    • Under "Source", select "GitHub Actions" as the source
    • Click "Save"
  2. Trigger the Documentation Deployment:

    • Push a commit to the main branch to trigger the documentation workflow
    • Or manually trigger the workflow from the GitHub Actions page
  3. Access Your Documentation:

    • Once the workflow completes successfully, your documentation will be available at: https://jchultarsky101.github.io/pcli2

Local Development

To preview the documentation locally:

# Install Oranda if you haven't already
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/oranda/releases/latest/download/oranda-installer.sh | sh

# Build the documentation
oranda build

# Serve locally (if you have a simple HTTP server)
cd public
python3 -m http.server 8000
# Then visit http://localhost:8000

Workflow Details

The documentation workflow (documentation.yml) will:

  • Automatically build documentation on pushes to the main branch
  • Deploy the documentation to GitHub Pages
  • Run on manual triggers via workflow_dispatch

Troubleshooting

If the documentation doesn't appear:

  1. Check that GitHub Pages is set to use "GitHub Actions" as the source
  2. Verify the documentation workflow ran successfully
  3. Check the workflow logs for any errors