install
Verify a signed .pkg and install it into an Organization from the terminal.
npx @elizon/cli install <artifact.pkg> --yes [--target=<name>] [--project=<project-id>]
[--slot.<id>=<value> …] [--approver.<node>=<emails>] [--form-user.<node>=<username>]
[--rename.<node>=<name>] [--trust=<public-key.json>] [--non-interactive] [--json]
[--activate [--acknowledge-evaluation] [--schedule.<trigger>.cron=… --schedule.<trigger>.timezone=…]]
npx @elizon/cli install <artifact.pkg> --resume=<installation-id> --yes [--target=<name>]
npx @elizon/cli install --rollback=<installation-id> --yes [--target=<name>]
npx @elizon/cli install <artifact.pkg> --activate=<installation-id> --yes [--target=<name>] [the same --slot flags]Installs a signed Package into an Organization. It does the same thing as the install wizard in Studio and runs on the same engine, but from a terminal or a CI job. That makes it the practical way to install one Package into many Organizations.
Needs a connected device and the package.install
permission (Owner, Admin, Editor).
What happens
Verify, offline
The signature is checked on your machine before anything is uploaded, against your
Organization's own signing keys (current and past) plus any key you pass with --trust.
✓ signature verified — ed25519:4f2c9a…
Self-signed by "Acme Ltd" (key ed25519:4f2c9a…). The name is the signer's own claim; no registry has counter-signed this Package.Work out what's missing, up front
The CLI reads the Package's Slots and Workflows and lists everything you still need to supply. In a
terminal it asks for each item. With --non-interactive, --json or no terminal, it fails with
every missing item in one message, so a CI job never fixes one item per run.
Install
The Organization creates every object in dependency order, binds each Slot to what you chose, and
records the install in the audit log. Without --activate it stops here, installed but not yet
live; the output says how to activate it.
✓ acme.triage-intake installed into acme (https://acme.internal:8443)
installation: 0f0b1c2d-…
status: installed
objects: 11Activating
Installing creates everything, inert. Activating makes the Package live: it runs the
evaluation suite, records the activation in the audit
log, publishes the entry point Workflow when a trigger needs it, and arms the triggers: schedule
timers, webhook addresses, api access, inbound-call phone routing, email and app polling,
and knowledge-document triggers. A manual trigger needs no arming. See
Triggers only fire when the Package is live.
Add --activate to install and activate in one run:
npx @elizon/cli install acme-triage-1.0.0.pkg --yes --activate \
--project=<project-id> --slot.reasoning=<llm-configuration-id> --slot.phone-line=<trunk-id>Evaluation: PASSED — 4/4 passed (gate: must-pass, recorded, not enforced)
✓ active-failure-escalates passed 5120 ms
…
✓ activated — status installed
✓ after-hours-call (inbound-call): Answering on +359…
✓ run-manually (manual): Runs from Studio.To activate a Package installed earlier without --activate, pass its installation id. Nothing is
created again:
npx @elizon/cli install acme-triage-1.0.0.pkg --yes --activate=<installation-id> \
--slot.reasoning=<llm-configuration-id> --slot.phone-line=<trunk-id>- The same
.pkg, and the same bindings. The organization never keeps the artifact or your answers, so activation needs them again. A different Package or version is refused. - Evaluation results are acknowledged by a person. If the Package has a suite, its results are
printed first. In a terminal you're asked to type
yes; otherwise pass--acknowledge-evaluation, which states that you have read what this run prints. Without either, activation stops withEVALUATION_NOT_ACKNOWLEDGED. The Package stays installed and inactive, and the error gives the command to finish. - Schedules run as the Package declares them unless you override them, both halves together:
--schedule.<trigger-id>.cron="30 7 * * 1-5" --schedule.<trigger-id>.timezone=Europe/Sofia. - Webhook addresses are generated at activation and printed with the trigger outcomes.
- A Package is activated once. Activating it again (from the CLI or Studio) is refused with
INSTALL_STATE_INVALID. An update arms the new version itself.
You can also activate from Studio: a Package installed but not activated shows Activate on its page in Studio → Packages. See Installed Packages.
Binding Slots: --slot.<id>=<value>
A Package never carries models, credentials, documents or phone lines. It declares Slots, and you fill each one. The Slot's declared type decides what the value means:
| Slot type | Value | Example |
|---|---|---|
llm | The id of one of your LLM Configurations | --slot.reasoning=4b1e… |
credential | A whole {{secret.KEY}} reference to your Secrets vault | --slot.calendar-access='{{secret.CALENDAR_TOKEN}}' |
knowledge-source | The id of a Knowledge Base holding the documents | --slot.policy-documents=9c07… |
stt, tts | <provider>:{{secret.KEY}} | --slot.speech-in='soniox:{{secret.SONIOX_API_KEY}}' |
sip-trunk | The id of one of your inbound SIP trunks | --slot.phone-line=77aa… |
A sip-trunk binding from the CLI carries no inbound number, so the Package's inbound-call triggers
stay unwired until the line is bound with its number in Studio. See
Voice and SIP → From the CLI.
Any Slot except llm accepts defer, which leaves it for later. The Package then installs as
installed-incomplete and lists the Slot as outstanding. Finish it later with
packages bind or Bind in
Studio, which take the same values as this table; a knowledge-source Slot is finished by adding
documents to its Knowledge Base. An LLM Slot can't be deferred, because nothing in a Package runs
without a model.
Credentials: references only, never values
The CLI never accepts a secret value, whether as a flag, from a file or on stdin. A credential
Slot takes only a whole {{secret.KEY}} reference to a Secret that already exists in the target
Organization. Anything else (a bare key name, a raw token) is refused before it leaves your
machine. Create the Secret first in Studio → Settings → Secrets. If one is missing, the error
includes a link to that page. --values and similar credential-file flags are refused by name.
OAuth credentials can't be completed in a terminal. A Slot with scheme: oauth2 fails with
SLOT_OAUTH_REQUIRES_BROWSER. Retrying won't help: install through the Studio wizard, or defer the
Slot and connect it in Studio afterwards.
Other options
| Option | Effect |
|---|---|
--yes | Required. Installing creates real resources. |
--target=<name> | Which connected Organization. Default: your default target. |
--project=<project-id> | Install into a project instead of the Organization level. The project must belong to the target's Organization. Required for Packages with a Knowledge Base. Without it, the Package's Agents, Teams, Workflows and voice configurations go into your Organization's default project. |
--approver.<node>=<emails> | Who approves a Workflow's human-review step (comma-separated emails). Keyed by the Workflow node id. |
--form-user.<node>=<username> | The username for a Workflow's password-protected form trigger. Never a password. |
--rename.<node>=<name> | Install an object under a different name, e.g. when the Organization already has one by that name. |
--trust=<file> | Also trust this signer's public-key document (elizon.signing-public-key.v1). See Sharing across Organizations. |
--non-interactive | Never prompt; fail listing everything missing. |
--activate | Activate after installing. See Activating. |
--activate=<installation-id> | Activate an existing, never-activated installation instead of installing. |
--acknowledge-evaluation | Acknowledge the evaluation results this run prints (for runs that can't prompt). |
--schedule.<trigger>.cron=, .timezone= | Override a schedule trigger at activation; pass both. |
When an install fails partway
The Organization records each object as it's created. If an install stops partway, it stays failed with a record of what exists, and nothing is left half-configured without a record. You choose what happens next, from the CLI or from Studio → Packages, whichever is handier:
# carry on from the object that failed (takes the artifact again)
npx @elizon/cli install acme-triage-1.0.0.pkg --resume=0f0b1c2d-… --yes
# remove everything this install created (takes no artifact)
npx @elizon/cli install --rollback=0f0b1c2d-… --yes--resume and --rollback can't be combined. A rollback won't delete an object that something
outside the Package now uses (INSTALL_ROLLBACK_BLOCKED). It's reported, and you decide.
Common errors
| Code | Meaning and fix |
|---|---|
PKG_UNSIGNED | The artifact isn't signed. Ask the author to run sign. |
PKG_SIGNATURE_INVALID | Contents don't match the signature. Don't install; get a fresh copy. |
PKG_UNKNOWN_SIGNER_KEY | Signed by an Organization whose key you haven't trusted. Pass its key with --trust. |
PKG_INCOMPATIBLE_PLATFORM_VERSION | The Organization's platform is older than the Package's minPlatformVersion. |
SLOT_CREDENTIAL_UNRESOLVED | The referenced Secret doesn't exist in the target Organization. Create it (link in the hint). |
SLOT_LLM_UNRESOLVED | That LLM Configuration doesn't exist, or none of its models meets the Slot's constraints. |
SLOT_LLM_NOT_DEFERRABLE | An llm Slot was given defer. |
SLOT_UNDECLARED | --slot.<id> names a Slot the Package doesn't declare (check the spelling). |
EVALUATION_NOT_ACKNOWLEDGED | The Package has an evaluation suite and this run couldn't acknowledge it. Read the results, then re-run with --acknowledge-evaluation. |
CLI_PROJECT_NOT_FOUND | The --project id isn't a project of the target's Organization. Check the id; if the project is in another Organization, connect a target for it (target add <host> --org=<organization-id>) and pass --target. Archived and deleted projects are refused the same way. |
INSTALL_STATE_INVALID | Activation refused: already active, not finished, or a different .pkg than was installed. The message says which. |
All codes: Error codes.
Example: one Package, three client Organizations
for client in client-a client-b client-c; do
npx @elizon/cli install triage-1.2.0.pkg --target="$client" --yes --non-interactive \
--activate --acknowledge-evaluation \
--trust=./acme-signing-key.json \
--project="$(cat "projects/$client")" \
--slot.reasoning="$(cat "llm/$client")" \
--slot.calendar-access='{{secret.CALENDAR}}' \
--slot.phone-line=defer \
--json > "install-$client.json"
done