Skip to content

himmelctl verb reference

himmelctl is the install, converge and offboard CLI. Run it as node <himmel-checkout>/scripts/himmelctl/bin.js <verb> (or the himmelctl shim if your install put one on PATH). bin.js --help prints the authoritative text; this page is the map of what each verb is for and what its exit codes mean.

Step-by-step install is setup/install.md; the four lifecycle paths (install, update, ensure, uninstall) are setup/updating.md. This page covers every verb, including the ones those pages only mention in passing.

Verbs at a glance

VerbMutates?One line
installyesWizard (or --scope / --from-profile) that wires himmel into a project or your user scope
statusnoSeverity diff of installed items against the desired manifest
ensureyesConverge the install toward the manifest; converge-only unless --prune
updateyesUpdate this checkout and its dependency chain (same engine as /himmel-update)
uninstallyesOffboard himmel; code only unless --purge-state
scopeyes (set)Read or switch the install scope
profileyes (lean/full/enable/disable)Inspect or toggle the plugin profile (same engine as /profile)
configyes (set)Toggle capabilities: initiative auto-ship steps, lanes, opt-in hooks
depsensure/upgrade onlyCheck, install or bump the declared toolchain
gapsnoWhat this setup lacks relative to a reference install profile
trustyesWire or unwire the trust shadow ledger’s hook entries
reportnoRead-only JSON config feed that the config UI renders; secrets show presence, never values. See ui.md
uinoRead-only config UI on 127.0.0.1 (needs bun); the operator runs it from a terminal. See ui.md
--version [--all]noVersion, describe string, commit; --all adds per-component currency

Shared flags: --dry-run / -n prints the plan and changes nothing, --json gives machine-readable output on status, deps status and gaps, --yes skips the confirmation on ensure, deps ensure, deps upgrade and scope set, and --items <a,b> scopes status / ensure to the listed item ids. -h / --help prints the usage text.

status

Read-only. Prints each desired item with a severity (green, degraded, red) for the install in the current scope. Run it from the adopted project’s root for project scope, or from the himmel checkout for user scope. Use --items to narrow it and --json to script it.

ensure

Installs or wires whatever status reports red or degraded. By default it is converge-only: it never unwires or disables an item that is no longer desired. That is a separate, higher-risk consent behind --prune, never bundled into the same prompt. --profile <core|luna|all> reconciles the target to that install profile first. Run it from the same location the matching install ran from.

update

Thin wrapper around scripts/himmel-update.sh, the engine /himmel-update uses: a full dependency-chain check and update with per-item status, aborting on the first failure. A release-tarball install in the versioned layout (<base>/<version>/ plus <base>/current) instead downloads, verifies and extracts the latest release into a new version directory and swaps current.

uninstall

Symmetric offboarding across both scopes. --dry-run lists every path, plugin, hook and settings key it would remove and touches nothing. The default removes himmel’s code only; operator state (Telegram pairing, bridge state) is kept unless you pass --purge-state. --yes is required when non-interactive.

ExitMeaning
0Torn down
2Refused (non-interactive without --yes) or incomplete teardown (a required step could not run)
3Declined by the operator, or teardown refused a wet run against a non-fixture HOME
otherThe teardown script’s own exit code

scope

scope get (alias scope status) prints the current scope. scope set <project|user> re-projects the install: it wires the target scope and unwires the old one, with an interactive confirm (--yes skips it, --dry-run prints the plan). It refuses to leave any item wired in both scopes (fail-closed).

ExitMeaning
0Done (or a dry run that predicts success)
1 / 2A real error, or a usage or consent problem
3Refused before any change was made. A --dry-run that predicts that refusal also exits 3

profile

Wraps scripts/machine-setup/plugin-profile.sh, the engine /profile uses.

Terminal window
himmelctl profile list [--json] # always-on tier and on-demand tier, enabled or disabled
himmelctl profile lean # the always-on set only
himmelctl profile full # also enable the on-demand set
himmelctl profile enable <spec> # one plugin
himmelctl profile disable <spec>

<spec> is plugin@marketplace, or a bare name when unambiguous. --dry-run prints the plugin-toggle commands instead of running them. This is the plugin profile; it is unrelated to the install profile that install and gaps read.

config

Bare himmelctl config asks nothing: it prints the link to the UI Configure page, where himmel capabilities are toggled without hand-editing files. When the UI service is not installed it says how to open the UI (himmelctl ui, or himmelctl ui --service install to keep it running). For scripts, the same settings the UI shows are read and written with:

Terminal window
himmelctl config get <path>
himmelctl config set <path> on|off
PathControls
initiative.<step>Initiative auto-ship steps (HIMMEL_INITIATIVE steps)
lanes.<id>Delegation lanes
hooks.plugin.<name>Opt-in hook plugins; set-only, runs claude plugin enable or disable

hooks.improveOnSubmit is a launching-shell env var, not settable here, and config get does not report hook state (exit 2).

deps

Operates on the toolchain declared in scripts/install/deps.json.

VerbEffect
deps statusRead-only version and presence check; --json for scripts
deps ensureInstall MISSING deps through their per-OS recipe
deps upgradeBump present deps toward latest; qmd’s model pull (about 2 GB) is gated behind a prompt or --with-models

gaps

Read-only. Diffs your saved install profile against a reference profile (default docs/setup/profiles/operator.install-profile.json; pick another with --preset <name>, which resolves to docs/setup/profiles/<name>.install-profile.json). It prints four groups:

  1. Answered off/none: your own choice, not a gap.
  2. Not recorded: the profile predates the question; not a choice.
  3. Reference-only: no wizard question can produce it yet (each carries its ticket).
  4. Present but unverified: recorded, but gaps is a static diff, not a live probe; run himmelctl status to confirm it is still wired.

It is a report, not a gate: it exits 0 whenever the report was produced, even when gaps exist.

trust

trust on|off|status wires, unwires, or reports the trust shadow ledger’s hook entries in this project’s .claude/settings.json. It is idempotent and off removes only what on added, so adding and removing it are both zero behaviour change. The hooks take effect on the next matching event, with no restart. trust status reports how many entries are wired (for example 7/7) and writes nothing. “Wired” is a different claim from “recording”: to confirm rows are actually landing, run node scripts/trust/shadow-ledger.mjs report and check for non-zero rows and a PROVEN collection line.

--version

himmelctl --version prints the himmel version, the git describe string and the commit. --version --all adds one line per updatable component (himmel checkout, plugins, Jira CLI, qmd, hermes, luna template, CLI-proxy pin, node/npm/bun) with installed against available. It is read-only.

ExitMeaning
0Everything current
1At least one component is behind
3Nothing is behind, but at least one is unknown

Install-time flags

FlagApplies toEffect
--scope <project|user>installNon-interactive install from the shipped adopter profile
--default-scope <s>installDefault answer to the scope question (still confirmable)
--from-profile <path>installRun non-interactively from a saved install-profile file
--contributeinstallLayer the contributor dev setup on top
--with-codex / --with-hermesinstallAdditionally select that lane (opt-in)
--lanes <csv>installv1 accepts only none
--purge-stateuninstallAlso remove operator state
--pruneensureOpt in to the disable phase
--with-modelsdeps upgradePull qmd’s embedding and rerank models
--no-networkensureRun only items whose manifest entry declares a no-network path (local file wiring); refuse the rest
--allow-agent-sessionuiOverride the refusal to start the config UI inside a Claude session
--deepreportAdd the wiring rows to the config feed