How to install IPM Registry offline
What's the most straight-forward way to install this on an offline server? I'm trying to set this up on an Azure DevOps server to support our CI/CD pipelines. I've tried using zpm installing the tgz from the local filesystem. I note zpm seems to need a repo configured to install but I can't work out how to setup a bare-bones Filesystem repo (please point me to some documentation on this). I have no idea what I'm doing...
zpm:%SYS>install f:/tmp/zpm-registry-1.3.4.tgz
ERROR! 'tmp' not found in any repository.
zpm:%SYS>install zpm-registry-1.3.4.tgz
ERROR! 'zpm-registry-1.3.4.tgz' not found in any repository.
zpm:%SYS>install zpm-registry
ERROR! 'zpm-registry' not found in any repository.
zpm:%SYS>install "f:\tmp\zpm-registry-1.3.4.tgz"
ERROR! 'f:\tmp\zpm-registry-1.3.4.tgz' not found in any repository.
zpm:%SYS>list
IPM (zpm) 0.10.6
zpm:%SYS>repo
1) Filesystem
2) ORAS
3) Remote Repository
Which sort of repository do you wish to configure? 1
Name: local
local
Source: F:\tmp\*
Enabled? Yes
Available? Yes
Use for Snapshots? Yes
Use for Prereleases? Yes
Is Read-Only? No
local
Source: F:\tmp\*
Enabled? Yes
Available? Yes
Use for Snapshots? Yes
Use for Prereleases? Yes
Is Read-Only? No
zpm:%SYS>install f:/tmp/zpm-registry-1.3.4.tgz
ERROR! 'tmp' not found in any repository.
zpm:%SYS>install zpm-registry-1.3.4.tgz
ERROR! 'zpm-registry-1.3.4.tgz' not found in any repository.
zpm:%SYS>install zpm-registry
ERROR! 'zpm-registry' not found in any repository.
zpm:%SYS>install "f:\tmp\zpm-registry-1.3.4.tgz"
ERROR! 'f:\tmp\zpm-registry-1.3.4.tgz' not found in any repository.
zpm:%SYS>info
Welcome to the Package Manager Shell (ZPM). Version: 0.10.6
Enter q/quit to exit the shell. Enter ?/help to view available commands
No registry configured
System Mode: <unset>
Mirror Status: NOTINIT
IRIS for Windows (x86-64) 2025.2 (Build 227U) Thu Jul 10 2025 11:01:07 EDT
Currently installed top-level modules are listed below:
IPM 0.10.6
Comments
The straightest path shown in the available material is:
- Install the built-in IPM client code if needed:
do $system.OBJ.Load($System.Util.InstallDirectory()_"dist/install/misc/zpm.xml","ck")
Then start the shell with:
zpm
- Configure a repository, because
installworks only “from a configured repository.” The IPM command reference explicitly says:
repo“configures the current namespace to search for modules on a remote server or on the local file system.”install“installs a module from a configured repository.”
1
- If you want a purely local/offline workflow, the documented local mechanism in the retrieved material is to use a local directory and
loada module from its manifest location. The docs state that modules can reside in “Local directories,” and give this example:
zpm:USER>load C:\InterSystems\IRISTest\ipm\mysample\1.0.0
It also says load is used to load the module into your local instance, specifying the location of the manifest file. 1
So, based on the returned documentation, the simplest offline approach is to place the unpacked module contents in a local directory containing module.xml, then use load <path> rather than trying to install a .tgz file path directly. 1
For a private-registry approach instead of direct local loading, the retrieved documents show that the supported pattern is to run zpm-registry, then point the client at that registry:
zpm:USER>install zpm-registry
zpm:USER>repo -n registry -r -url https://registry.yourdomain.com
The package page says you can “build your own private registry to have the option to install packages with ZPM client from your private registry,” and the setup article shows changing the client to that registry with:
zpm: USER>repo -n registry -r -url http://localhost:52773/registry/ -user <username> -pass <password>
After that, install modulename works against that configured registry. 23
For documentation on this:
- General IPM usage, repositories, local directories,
install, andload: Introduction to InterSystems Package Manager. 1 - Private registry setup and how to point ZPM at it: Setting Up Your Own InterSystems ObjectScript Package Manager Registry. 3
zpm-registrypackage page and README link: zpm-registry. 2
What the retrieved docs do not show is a documented command for installing a .tgz artifact directly by filesystem path with install. Instead, they describe:
install modulenamefrom a configured repository, andload <directory>from a local module directory. 1
So for your exact case, the most straightforward documented options are:
- use
loadfrom a local unpacked module directory containingmodule.xml, or - stand up a private
zpm-registryand configurerepoto point to it, theninstall modulename. 123
Sources:
Try 'load' command instead of 'install'
Thanks, yes that did it. So, I had to extract the tgz first, then simply "load f:/tmp/zpm-registry" (confirming that the folder zpm-registry contains module.xml. I assumed a Filesystem repository could contain tgz files and it would know what to do with them.
Or, to use "install zpm-registry" I can add a Filesystem repository that contains just this one folder "f:/tmp/zpm-registry". That's what threw me, I assumed a "repository" would contain multiple folders, or packaged modules in tgz format even.
zpm:USER>repo
1) Filesystem
2) ORAS
3) Remote Repository
Which sort of repository do you wish to configure? 1
Name: zpm-registry
Root File Path: F:\tmp\zpm-registry
zpm-registry 1.3.4 @ F:\tmp\zpm-registry\
zpm-registry
Source: F:\tmp\zpm-registry\*
Enabled? Yes
Available? Yes
Use for Snapshots? Yes
Use for Prereleases? Yes
Is Read-Only? No
zpm:USER>install zpm-registry
WARNING: The resource tag is deprecated and may be removed in a future release of IPM.
Please contact the package developer of zpm-registry to use instead
WARNING: The {$dbrole}/${dbrole} expression is deprecated. Please contact package developer to use {$globalsDbRole} instead.
Building dependency graph...Done.
[USER|zpm-registry] Initialize START
[USER|zpm-registry] Initialize SUCCESS
[USER|zpm-registry] Reload START (F:\tmp\zpm-registry\)
[USER|zpm-registry] Reload SUCCESS
[zpm-registry] Module object refreshed.
[USER|zpm-registry] Validate START
[USER|zpm-registry] Validate SUCCESS
[USER|zpm-registry] Compile START
[USER|zpm-registry] Compile SUCCESS
[USER|zpm-registry] Activate START
[USER|zpm-registry] Configure START
[USER|zpm-registry] Configure SUCCESS
[USER|zpm-registry] Activate SUCCESS
zpm:USER>
Happy days! Though, easier to just use "load" and skip the step to create the Filesystem repository entirely.
You can call "load" directly on a tarball, but if you set up a file system repository, IPM expects the module to be untarred/unpacked into directories already.
This is how I have been setting up IRIS instance local filesystem registries. I'm still using an old 0.9.1 version so your version might behave differently.
The repository location is recorded by environment variable IPM_LOCAL_REGISTRY.
In ObjectScript shell %SYS namespace:
// install ipm
do $system.OBJ.Load("/path/to/zpm-0.9.1.xml","ck",.errorlog)
// setup local filesystem ipm registry
zwrite ##class(%IPM.Main).Shell("repo -name REPONAME -filesystem -depth 2 -path ${IPM_LOCAL_REGISTRY}")A (minimized) bash script used to install module tarballs:
#!/bin/bash
declare -r tarball=${1}
declare -r workdir=$(mktemp --directory --tmpdir=/tmp ipm-module.XXXXXX)
trap "rm -rf ${workdir}" EXIT
declare -r manifest=${workdir}/module.xml
tar zxf ${tarball} -C ${workdir}
declare -r name=$(perl -ne 'if (m/<Name>(.*?)<\/Name>/) { print "$1"; last; }' ${manifest})
declare -r version=$(perl -ne 'if (m/<Version>(.*?)<\/Version>/) { print "$1"; last; }' ${manifest})
declare -r module_dir=${IPM_LOCAL_REGISTRY}/${name}/${version}
if [[ -d ${module_dir} ]]; then
echo "Module ${name} version ${version} is already in the local registry"
exit 0
fi
mkdir -p ${module_dir}
cp -r ${workdir}/* ${module_dir}It will untar the tarball, figure out the module name and version from the manifest file and copy the sources to correctly named directory.
I also have other scripts that will fetch the tarballs from the actual artifact repository where the module tarballs are stored.