xmatix package turns metadata you built in a development tenant into a versioned package and installs it into another tenant: you write a manifest, build an artifact from it and one or more seed-pack files, ask the server to check it, then install, upgrade or uninstall it. It sits after metadata pull, which produces the seed-pack files, and alongside Setup → Design Studio → Packages, where the same installations appear for administrators.
Overview
xmatix package init <package-id> [--namespace <ns>] [--publisher <name>] [--display-name <name>]
xmatix package build --manifest <package.json> --seedpack <file.json> [--seedpack <file.json> …]
[--mode full|delta] [--deletes <deletes.json>] [--out <path>]
xmatix package validate <artifact.json> [--upgrade]
xmatix package install <artifact.json> [--upgrade] [--wait] [--yes]
xmatix package list
xmatix package logs <package-id>
xmatix package uninstall <package-id> [--wait] [--yes]
init and build work only on files in your workspace. validate, install, list, logs and uninstall call the signed-in tenant.
When to use it
- Ship a set of custom entities, fields, views and layouts as one unit that installs the same way into many tenants and can be upgraded or removed later.
- Check a package against a tenant before installing it — the validate step reports blockers and a row count without changing anything.
- Install or remove a package from a pipeline —
--yesskips the prompts and--waitgives you an exit code that reflects the final status.
To copy a tenant's own customizations from one tenant to another without packaging them, use metadata push or migrations instead. Publishing a package to the catalog that administrators install from is not a CLI operation.
How xMatix handles it
The artifact. package build writes one JSON file holding the manifest and every seed pack, in the order you gave them. Each pack is numbered from 1. The command prints the artifact's size and its SHA-256 hash, which you can record with the release.
Ownership. When an install succeeds, the platform records every row the package delivered as owned by that package. Uninstall deletes exactly those rows. validate flags any row in your artifact that a different package already owns.
Install, upgrade and uninstall run as background jobs. The server checks the request first and refuses it at once if a check fails. If the checks pass, it records the installation as Queued and returns. The status then moves through Installing (or Upgrading or Uninstalling) to Installed, Uninstalled, Failed or ValidationFailed. An install applies all of its seed packs in one transaction, so a failure leaves nothing half-applied. Only one package operation runs at a time in a tenant.
Upgrades keep the tenant's own rows. During an upgrade, any row the tenant has claimed as its own is left out of the incoming packs. The install log then says how many tenant-owned rows were skipped.
Editable or locked rows. The manifest's editablePolicy.allowTenantEdits decides how installed rows behave. When it is false (the default init writes), the rows are installed as standard metadata. Where the standard-metadata lock is enforced, administrators can then only switch those rows on or off or change which one is the default. They cannot edit or delete them, and must clone a row to change it. When it is true, the rows install as ordinary custom metadata.
Prerequisites
- A workspace (
xmatix init) and a signed-in session (xmatix login). See Authentication. - The Manage metadata packages capability (
setup.metadata.packages.manage) on the signed-in identity, in every tenant you validate or install into. The same capability opens Setup → Design Studio → Packages. - For a managed package, a namespace. Every row's name in the package must start with that namespace followed by
.,-or_, for exampleacme_ServiceVisit.
Procedure
Step 1 — Scaffold the manifest
xmatix package init com.example.field-service --namespace acme --publisher "Example Publisher" --display-name "Field service extensions"
The CLI writes xmatix/packages/com.example.field-service/package.json and prints the next two commands to run. The manifest starts as a managed package at version 1.0.0, with no dependencies, tenant edits off and tenant extensions on. If the manifest already exists, init stops with "Manifest already exists" and changes nothing.
Step 2 — Author the metadata and pull it
Build the entities, fields, views and layouts in a development tenant, naming every row with the namespace prefix. Then pull just those rows into the package folder:
xmatix metadata pull --scope Namespace --namespace acme --out xmatix/packages/com.example.field-service/v1.json
The Metadata page explains the Namespace scope.
Step 3 — Build the artifact
xmatix package build --manifest xmatix/packages/com.example.field-service/package.json --seedpack xmatix/packages/com.example.field-service/v1.json
The CLI prints Built <path> with the size, then SHA-256: and the hash. By default the artifact is written next to the manifest as <packageId>-<version>.artifact.json. Repeat --seedpack to include several packs; they are applied in the order given.
To remove rows that an earlier version of the package delivered, list them in a deletes file — a JSON array of { "tableName": "…", "naturalKey": "…" } objects — and pass --deletes. The CLI merges the list into the last seed pack, switches that pack to delta mode and prints how many deletes it merged. Only rows the seed engine manages are deleted, children before parents.
Step 4 — Validate against the target tenant
xmatix package validate xmatix/packages/com.example.field-service/com.example.field-service-1.0.0.artifact.json
Nothing is written. The CLI prints VALID or INVALID, then each error and warning, then a line such as Diff: create=42 update=0 delete=0. The exit code is 0 when valid and 1 when not. Add --upgrade to validate the artifact as an upgrade of the installed version.
Step 5 — Install
xmatix package install xmatix/packages/com.example.field-service/com.example.field-service-1.0.0.artifact.json --wait
The CLI asks "Queue install of '<package-id>' into the current tenant?" (answer y, or pass --yes). It then prints Queued. and how to track the job. With --wait it checks every 3 seconds and prints each status change until the package reaches Installed (exit 0), Failed or ValidationFailed (exit 1), or 10 minutes pass. A timeout exits 1 with "Timed out waiting for a terminal status (job may still be running)" — the job carries on, so check package list. If the tenant runs the job straight away instead of queueing it, the CLI prints "Applied inline (no queue configured)".
Step 6 — Check the result
xmatix package list
xmatix package logs com.example.field-service
list shows a table of every package installation in the tenant: Package, Kind, Version, Status, Enabled and Installed (UTC). logs prints the newest 200 log entries for one package, newest first, as <time> <step>/<status> <message>. Failed entries are red and completed ones green. Administrators see the same installations on the Installed tab of Setup → Design Studio → Packages, where View logs on a row opens the same log.
Step 7 — Upgrade to a new version
Raise version in the manifest (for example to 1.1.0), pull and build again, then validate and install with --upgrade:
xmatix package validate <artifact> --upgrade
xmatix package install <artifact> --upgrade --wait
The target version must be newer than the installed one, and the installed package must be in the Installed status.
Step 8 — Uninstall
xmatix package uninstall com.example.field-service --wait
The CLI warns that uninstall removes every row the package owns from the current tenant and asks "Continue?" (pass --yes to skip). It prints "Uninstall queued." and, with --wait, follows the status to Uninstalled. Uninstalling a package that is not installed does nothing.
Fields
The manifest (package.json) that init writes:
| Field | What it means | Notes |
|---|---|---|
packageId | The package's stable id, such as com.example.field-service | Required. Identifies the package in every later command; never change it between versions |
publisher | Who publishes the package | Required. init writes the placeholder <publisher> when you leave out --publisher — replace it |
displayName | The name administrators see | Required. Defaults to the package id |
namespace | The prefix every row name in the package must carry | Required for a managed package |
packageKind | The kind of package | init writes ManagedPackage, shown as Package on the Packages screen |
version | The package version, such as 1.0.0 | Required. An upgrade must use a newer version |
description | A short description | Optional |
minPlatformVersion | The lowest platform version the package installs on | Optional. Install is refused on an older platform |
dependencies | Packages that must already be installed | Optional. Each entry is a package id, or id@version to require that version or newer |
editablePolicy.allowTenantEdits | Whether the tenant can edit the installed rows | false by default. See How xMatix handles it |
editablePolicy.allowTenantExtensions | Whether the tenant can extend the package | true by default |
protectedObjects | Objects the package protects | Empty by default |
Business rules
validate runs every check below. Install and upgrade run them again, except the ownership check, which only validate reports — so validate before you install. A failed check refuses the request and nothing is installed.
- Manifest.
packageId,displayName,publisherandversionmust be filled, and the artifact must contain at least one seed pack.buildchecks the same fields before it writes anything. - Namespace. A managed package needs a namespace, and every row in its seed packs must be named with it (translations are exempt). The error names the first row that is not.
- Platform version. When
minPlatformVersionis set, the tenant's platform must be that version or newer. - Dependencies. Each dependency must be installed, and at the required version or newer when one is given.
- Install versus upgrade. Installing the version that is already installed is refused — use upgrade. Upgrading needs an installed package and a newer version.
- Ownership conflicts.
validatereports a row already owned by a different package as an error. A row the tenant owns is not an error: it is skipped on upgrade, andvalidatelists it as a warning. - Licence. Where package licensing is enforced and the package requires a licence, the tenant needs an active licence for it.
- Removal. A package cannot be uninstalled while another installed package lists it as a dependency, or when it is marked as not removable.
- One operation at a time. A second install or uninstall in the same tenant waits for the first, and gives up with "Another package operation is in progress for this tenant. Retry shortly." if it waits too long.
Example
A partner builds a "Field service extensions" package for its customers. In its development tenant it creates an entity named acme_ServiceVisit with six fields, a list view and a record layout, all prefixed acme_. It runs package init com.example.field-service --namespace acme --publisher "Example Publisher", pulls the acme namespace into v1.json and builds the artifact. package validate against a customer's test tenant prints VALID and Diff: create=14 update=0 delete=0. package install --wait prints Queued., then each status as it changes, ending with status=Installed and Done. The new entity now appears in the test tenant, and the package shows as Installed under Setup → Design Studio → Packages.
A month later the partner adds a field, sets version to 1.1.0, rebuilds and runs package install --upgrade --wait. The log ends with "Package 'com.example.field-service' applied successfully."
Training
Practice exercise
In a sandbox tenant, scaffold a package with the namespace train, create one entity named train_Checklist with two fields, pull the train namespace, build and validate the artifact, install it with --wait, then uninstall it with --wait.
Expected result: validate prints VALID with a non-zero create count. install --wait ends with Done., and package list shows the package as Installed. After uninstall --wait, package list shows it as Uninstalled and the entity is gone from the tenant.
Quick reference
init→metadata pull --scope Namespace→build→validate→install.- Every row in a managed package must start with the namespace and
.,-or_. validatewrites nothing; exit code 0 means valid.installanduninstallqueue a job — add--waitfor a meaningful exit code.- Upgrades need
--upgradeand a newerversion. --deletesremoves rows an earlier version delivered and turns the last pack into a delta pack.- Uninstall deletes every row the package owns.
package logs <id>is the first place to look when a status is Failed.
Permissions
Every package command that contacts the tenant (validate, install, list, logs, uninstall) needs the Manage metadata packages capability (setup.metadata.packages.manage). Without it the server answers 403, and the CLI prints Validate failed:, Request failed:, List failed:, Logs failed: or Uninstall failed: with that response. init and build need no permission because they only touch local files. Grant the capability through the identity's security profile — see the security model.
Configuration
- Workspace and connection —
xmatix initandxmatix loginset which tenant the commands reach. See Workspace layout and Authentication. - Where package files live —
xmatix/packages/<packageId>/holds the manifest, and by default the artifact. Commit the manifest and the seed packs you build from. - Packages screen — Setup → Design Studio → Packages lists installations on the Installed tab (View logs, Uninstall) and published packages on the Catalog tab (Install). The header shows Installed, In progress and Catalog available counts.
- Editable policy — set
editablePolicy.allowTenantEditsin the manifest before the first install to decide whether tenants can edit the package's rows.
Common problems
"Manifest field 'publisher' is required."
build found an empty required field in the manifest. Fill packageId, publisher, displayName and version, then build again.
"Managed packages require a 'namespace' in the manifest."
The manifest's packageKind is ManagedPackage but namespace is empty. Add the namespace you used for the row names.
Validate reports a row that "is not namespace-qualified"
A row in a seed pack is not named with the package's namespace. Rename it in the development tenant, or pull with --scope Namespace so that only namespaced rows are included.
"Object '…' is already owned by a different package."
Another installed package owns that row. Rename the row in your package, or uninstall the other package first.
"Package '…' version … is already installed. Use upgrade for newer versions."
You ran a plain install of the installed version. Raise version in the manifest, rebuild, and install with --upgrade.
"Upgrade target version … must be newer than installed version …"
The manifest version is not higher than the installed one. Raise it and rebuild.
"Dependency '…' is not installed."
A package listed in dependencies is missing, or not in the Installed status, in the target tenant. Install it first.
"Package '…' depends on '…' and blocks its removal."
Another installed package depends on the one you are removing. Uninstall the dependent package first.
The install ended as Failed or ValidationFailed
Run xmatix package logs <package-id>. The newest failed entry carries the reason. Fix the cause, rebuild if needed and install again — never edit the package's rows by hand to finish a half-done install.
"Timed out waiting for a terminal status"
--wait gave up after 10 minutes but the job may still be running. Check xmatix package list until the status is final.
Common questions
Does validate change anything in the tenant?
No. validate runs the same checks as install and compares the artifact with the tenant's rows, then reports the result. It prints how many rows would be created, updated and deleted, and lists the blockers as errors and the tenant-owned rows that an upgrade would skip as warnings. It returns exit code 0 only when there are no errors, so a pipeline can run it as a gate before install.
Can I install from the package catalog with the CLI?
No. The CLI installs artifacts you built yourself. Packages published to the catalog are installed from the Catalog tab of Setup → Design Studio → Packages. Both kinds appear together in xmatix package list and on the Installed tab. Publishing a package to the catalog is not something a tenant can do from the CLI or the Packages screen.
What does package list show?
Every package installation in the tenant, whatever installed it: packages you installed from the CLI, packages installed from the catalog, and platform modules. The Kind column tells them apart, and Status shows where each one is, including packages that were uninstalled or that failed. Use xmatix package logs <package-id> on any row to see the history of its installs, upgrades and uninstalls, newest first.
Why did my upgrade skip some rows?
During an upgrade, rows the tenant has claimed as its own are protected from being overwritten. The install log states how many were skipped, and validate --upgrade lists them as warnings beforehand.
