lumenflow:upgrade
lumenflow:upgrade
Section titled “lumenflow:upgrade”Upgrade LumenFlow packages; bridges the legacy npm scope to the private licence registry
Git object durability: this command sets repository-local core.fsync=committed
and core.fsyncMethod=batch (git 2.37.0 or newer), so git objects survive an unclean shutdown.
Lane worktrees share the setting, and a stricter value you already set is kept.
To opt out, set software_delivery.git.object_durability to false with pnpm config:set.
Recovery steps for damaged objects: Troubleshooting.
Cross-scope upgrade bridge: default and --latest upgrades use the private licence registry
named in your licence and migrate legacy @lumenflow/* declarations to @hellmai/lumenflow-*,
including partial migrations. Configure @hellmai:registry for that registry and keep the
licence key (Base64 _password) or read token (_authToken) in private npm configuration
outside Git. The owner chooses free or
paid grants; consumers need no GitHub account or seat. Revocation prevents future downloads,
not use of already installed files. Package metadata proves access; npm whoami is not used.
Real upgrades refuse unavailable or denied metadata; dry runs report it without modifying files.
When the registry refuses the credential, the error carries the registry code and detail
(LICENSE_EXPIRED, LICENSE_SUSPENDED, ACCESS_DENIED or any other code), the expiry date when
known, and the renewal route; lumenflow:doctor checks the same credential ahead of time. See
diagnose and renew an expired registry credential.
An explicit historical --version pin in a legacy-only project retains its original scope and registry.
See Installing with a LumenFlow licence.
Validated upgrade transaction
Section titled “Validated upgrade transaction”Upgrade preflight checks the planned workspace, source and historical WU migrations before any writes.
--dry-run performs the same validation and reports planned changes without modifying files.
Every transformed historical record must satisfy the current WU writer schema. Invalid records
and conflicting preserved values are reported together with their paths; fix those records and retry.
Legacy phase: values are preserved as legacy_phase. A positive numeric phase also becomes
initiative_phase when the record declares an initiative and has no existing initiative phase;
human phase labels are preserved without guessing an initiative phase. Historical deprecated
statuses become superseded, retaining legacy_status: deprecated, including records without
a phase. Existing notes and history are preserved. The migration is idempotent.
The package declarations, lockfile, workspace, source, WU history and state migration are published in a single upgrade commit. Package installs run noninteractively. Before reporting success, the upgrade verifies the installed package versions in both the upgrade worktree and the consumer checkout.
Only verified exact default 6.1.6 generated CI bytes (raw or formatted, LF or CRLF) are adopted inside that same transaction. User bytes outside existing ownership markers are preserved. Other unmarked or customized workflows refuse before publication when CI enforcement is enabled; disabled CI preserves authored workflows. Dry-run uses the same ownership check.
Missing test_full and test_incremental commands are backfilled only from existing project
evidence. A declared Vitest dependency plus its root config permits a full runner command when
no test script exists. Existing authored commands, including explicit blank strings, are preserved;
non-node presets and testing:none are not assigned Node test commands. Invalid command values refuse.
Verify the prep log actually executes the declared tests; PASS alone does not prove execution.
Target CLI execution
Section titled “Target CLI execution”Upgrades must execute the target CLI code. Bootstrap requires 1 GiB free; bootstrap failures refuse
the installed CLI fallback. --no-bootstrap is an internal handoff that requires the executing CLI
version to match the target version. Frozen clients predating this fix can still fall back silently:
invoke the exact target CLI upgrade entry when migrating those clients.
Consumer packs declaring a v6-era kernel/host range
Section titled “Consumer packs declaring a v6-era kernel/host range”From 1.0.4, kernel start checks each pack against the real kernel version. A local pack made by
pack:author or pack:scaffold up to 1.0.3, or in the 6.x era, declares ^6.0.0 for kernel and
host. The upgrade rewrites that range in each source: local pack’s manifest.yaml to the new
line’s range (^1.0.0), refreshes the pack’s workspace.yaml integrity pin, prints each change
and lists it in the upgrade commit. --dry-run shows the same list. Any other range the new
version does not satisfy, or a pin that no longer matches its pack, stops the upgrade before any
change and names the file, field and range to fix by hand.
Mixed-version lifecycle window
Section titled “Mixed-version lifecycle window”Upgrading the installed CLI package crosses a window where a lifecycle handoff receipt minted by
the OLD version’s wu:brief/wu:prep can be presented to the NEW version’s wu:done (or the
reverse, on a downgrade). A refusal in that window now names one of these reasons instead of a
single opaque message, and always prints a remedy naming the exact command to re-run:
receipt_forged— the receipt could not be decoded, or failed schema/digest validation (this is the code you see when a receipt minted by an incompatible schema version cannot be parsed at all).receipt_not_yet_valid/receipt_expired— the receipt’s validity window does not cover now.receipt_operation_not_allowed— the receipt does not authorize the operation you ran.receipt_context_mismatch— the receipt’s owner, subject, policy, protected payloads, or HEAD no longer match this claim.receipt_not_recorded— the receipt is not present in this worktree’s durable receipt journal.
Every case: re-run pnpm wu:brief --id <WU> on the version you are running now to mint a current
receipt.
Upgrading with work in flight
Section titled “Upgrading with work in flight”Supported window: upgrading one release at a time while a WU is claimed needs no extra receipt step.
A lifecycle handoff receipt minted by the previous release’s wu:brief stays valid under the
new release for its own 24-hour lifetime, for the operations it was minted for (a receipt minted
by 1.0.0-rc.4 through 1.0.1 authorizes wu:prep, wu:done and wu:recover, not wu:rebase,
which is refused as receipt_operation_not_allowed).
receipt_policy_unrecognized— the receipt was minted under a lifecycle policy this CLI version does not recognise, usually by a newer CLI before a downgrade. Re-runpnpm wu:brief --id <WU>under the CLI version that will run the command.telemetry_pack_pin_version_skew—wu:doneprints this warning whenworkspace.yamlpins a pack from a different CLI version than the one running. Telemetry still loads from the running CLI’s bundled pack. Runpnpm lumenflow:upgradeto repin, or install the CLI version the pins name. A pin that cannot load at all is audited to.lumenflow/force-bypasses.logunder the same name.
Older releases cannot change. 1.0.0-rc.4 refuses every receipt minted by 1.0.2 or later with
wu:done lifecycle handoff receipt failed read-only binding verification: before a downgrade to
it, re-run wu:brief under 1.0.0-rc.4. 1.0.0-rc.4 under newer pins auto-degrades telemetry with
an audited Pack manifest version mismatch warning, and 1.0.2 under other pins self-heals
without a warning: finish the upgrade so the running CLI matches the pins.
Upgrading on main while claims are live
Section titled “Upgrading on main while claims are live”From 1.0.10 a same-scope upgrade from the main checkout (package pins, lockfile, workspace.yaml
pack pins, managed docs, hooks and the marker) runs while WUs are claimed. It writes nothing into
any claim worktree and touches no claim, lane branch or WU record. Before publishing it holds each
live claim’s wu:done completion lock on this host for at most 2 seconds; a held lock refuses with
WU-X is completing and origin unchanged. After the install it prints, per live claim, the commands
its holder runs with its own session. A bound claim needs no policy refresh: the main
checkout’s new release rebases it from its worktree (a pin taken by an earlier release verifies
across the upgrade), then the frozen install, wu:brief and wu:prep run in the worktree. A
pre-binding claim keeps one wu:repair --claim --integration-target --refresh-policy first.
The refresh holds and restores the claim’s own generated audit append and checkpoint rows itself
(--check previews the paths), so a claim that has run wu:prep or mem:checkpoint needs no manual
Git step; any other change in the claim worktree refuses before anything is published, naming the path.
The notice counts claims by class: those that need a policy refresh and those that keep a
valid pin and need wu:rebase plus install before wu:prep and wu:done. The CLI version skew
refusal stays strict, never reuses a prep checkpoint from an older release, and prints the same
rebase and install commands.
An upgrade that migrates WU records, state, workspace, CI or source, or bridges the package scope,
still refuses while claims are live. --adopt-claimed-wu is not needed for ordinary upgrades.
One engine runs the whole route: the repair and the claim worktree steps both run under
the main checkout’s upgraded release, and the engine never compares a claim’s engine version with
the running one. A claim made under an earlier 1.0.x needs no old-release root; a harness that
asserts a per-claim engine version creates the two-root conflict, so remove that assertion.
See Upgrading on main while claims are live.
Workspace consumers
Section titled “Workspace consumers”From 1.0.10 the upgrade pins @hellmai/lumenflow-* in every workspace package, not only the root:
each member matched by the pnpm-workspace.yaml packages: globs (or the npm, yarn or bun
workspaces field) that declares a cohort package gets the exact target version in its own
dependency section, in the same upgrade commit. workspace:, link:, file:, catalog: and
alias declarations are left as written. The same pin applies to every other git-tracked package.json that declares a cohort
package, such as spikes/* or templates/* outside the workspace globs; copies under node_modules and untracked
files are never touched, and the upgrade prints each manifest it re-pinned. After the install the upgrade refuses, before committing,
when the lockfile still resolves more than one version of any @hellmai/lumenflow-* package,
printing each version and the workspace importers that reach it; lumenflow:doctor reports the
same split as an error. See Workspace consumers.
workspace.yaml is edited key by key
Section titled “workspace.yaml is edited key by key”lumenflow:upgrade edits only the workspace.yaml keys it owns: the built-in pack pin under packs,
the obsolete 5.x software_delivery.state block, and a generated test_incremental command. Each edit
goes through the same document-preserving writer as lumenflow:enable, so comments, quoting, long
wrapped strings and key order elsewhere stay byte-identical, and a second upgrade leaves the file unchanged.
Managed-document dry-run preview
Section titled “Managed-document dry-run preview”--dry-run lists the shared docs-sync file plan with new file or template change reasons.
Unchanged and stamp-only files are not written. Existing local additions and project-owned
tool adapters stay untouched; a first-upgrade preservation backup is labeled separately.
The claim-policy content digest before and after the managed-document plan uses the same
function as claims and names the responsible files. This holds current workspace policy fixed;
the FINAL digest is computed when shared workspace planners prove no effective policy rewrite.
Unprojected workspace writes make the final digest explicitly unavailable; new pack identities
or local-to-builtin source changes can move it with no document changes.
A same-version no-op reports no document writes and an unchanged final digest; —force syncs.
The preview grants no claim authority.
Exact template previews require the executing target CLI. A different or unresolved target
reports unavailable templates and digest prediction; invoke the exact target upgrade entry
with --dry-run. An unreadable policy never produces an unchanged verdict.
A sync with no content change leaves managed docs untouched
Section titled “A sync with no content change leaves managed docs untouched”Managed docs render a Last updated date stamp. When the newly rendered doc differs from the file on disk
only in that stamp line, the sync leaves the file byte-identical, so an upgrade on a later day does not
change LUMENFLOW.md and does not stale the claim policy pin, which hashes it raw. When the content
really changes, the doc is written with the new stamp as before. One shared helper serves docs:sync,
the skills and onboarding sync, and init --force.
One version pin point for pnpm workspaces
Section titled “One version pin point for pnpm workspaces”When pnpm-workspace.yaml defines a catalog entry for an @hellmai/lumenflow-* package (the
default catalog: or a named catalogs: map), that entry is the one pin point. The upgrade rewrites
the entry to the target version, leaves every catalog: reference in the root and the members
alone, and refreshes the lockfile, so the commit changes the catalog entry and the lockfile only.
pnpm update -w pkg@x is not run for a package reached through a catalog entry: pnpm would replace
the catalog: reference with the literal version and leave the entry stale. Entries whose value is
not a registry version (workspace:, file:, link:) are not touched.
Hard-coded engine pins left in the root and workspace members are still re-pinned in place, and the
upgrade lists each one with its file path plus the one command that converts them:
pnpm lumenflow:upgrade --version <x.y.z> --use-catalog --force. Nothing is converted without
--use-catalog; with it, hard-coded pins become catalog: references and one default catalog entry
is created, so later upgrades edit only that entry.
The release-age exemption stays exact and is managed for you, and it is an approval, not a default.
Where the installed pnpm parses pkg@version entries in minimumReleaseAgeExclude (pnpm 10.19.0 and
later, checked with pnpm --version in the project), an explicit --version X is the same human
approval pnpm asks for interactively: before the install the upgrade adds X for the engine packages
the project uses, so a strict minimumReleaseAge policy does not stop it, and the running engine must
be X. On the default and --latest paths the registry chooses the version, so nothing is
pre-approved: a strict policy makes pnpm refuse and the error prints the approving command,
pnpm lumenflow:upgrade --version followed by that version. After every install the entries the upgrade owns are pruned to the versions each directory’s
lockfile still resolves. Entries for other packages, ranges, name patterns and unknown names are never
changed. A scope pattern is deliberately not written: it would let any freshly published package in the
scope skip the release-age delay. Older pnpm keeps today’s behaviour and nothing is written.
--adopt-claimed-wu is unchanged by this section.
See One pin point.
Nested lockfiles and the sync sidecar
Section titled “Nested lockfiles and the sync sidecar”When a re-pinned manifest sits beside its own lockfile (pnpm-lock.yaml, package-lock.json,
yarn.lock or bun.lock, as spikes/* and templates/* do), the upgrade refreshes that lockfile
in the same governed commit with a lockfile-only install run in the project directory, then proves
it with the project’s own frozen install. pnpm projects that are not their own pnpm root are run
with --ignore-workspace --lockfile-dir .. Workspace members need nothing extra: their importers live in the root
lockfile. If any nested lockfile cannot be refreshed the upgrade refuses before committing or
publishing, naming each project and the exact command to run, so no per-upgrade lockfile work unit
is needed. The reconcile after publication also leaves every file the Cloud sync sidecar owns
alone: control-plane-sync.json and telemetry/cloud-sync-state.json under
.lumenflow/state/packs/software-delivery/. Sidecar-owned state is excluded from the transaction
baseline and from restoration, so a sidecar write during the upgrade is never a “changed since the
transaction baseline” conflict. The set is one exported definition that the sidecar’s own writers
also use, so a file the sidecar adds later is excluded without a separate upgrade change.
Reconciliation after publication
Section titled “Reconciliation after publication”From 1.0.12 the legacy-state check around the main fast-forward compares only the legacy files the
upgrade copied from the main checkout into its staged migration. Files the upgrade’s checkout got
from git (such as tracked old .lumenflow/telemetry/*, which the upgrade untracks) are not
compared, and with migration-complete.json present the check is skipped: the staged migration
reads no legacy input. Agent session writes (display-name-reservations.jsonl, the conductor
outbox) and the pruning of lifecycle-enforcement/mutations/ receipts by live claims no longer
fail the upgrade. If reconciliation still fails after the push, the upgrade names the changed
paths and prints the commands that finish it: pnpm git:sync-main (when main is not yet
fast-forwarded), the frozen install, a version check and pnpm lumenflow:doctor. Do not re-run
the upgrade. See Troubleshooting.
Options:
| Flag | Description | Required |
|---|---|---|
-l, --latest | Upgrade to latest version With —version, keeps the cross-scope migration intent and installs exactly that version (the self-bootstrap handoff uses this form) | No |
-n, --dry-run | Validate planned migrations and show commands without writes List managed-document writes, reasons and claim policy digest effect. Exact document previews require the executing target CLI; unavailable target templates/digests are reported explicitly. Unchanged and stamp-only documents are not rewritten. | No |
-f, --force | Run the full sync flow even when already on the target version (bypasses the no-op short-circuit) | No |
--no-bootstrap | Internal bootstrap handoff; executing CLI must match target Bootstrap failure refuses the installed CLI fallback. | No |
--adopt-claimed-wu <WU> | With an exact —version, from the WU’s own worktree: pin the private cohort in every workspace package, lockfile, marker in one hooked commit (no push, no —dry-run) | No |
--use-catalog | Opt in (pnpm workspace): convert hard-coded @hellmai/lumenflow-* pins in the root and members to catalog: references; later upgrades edit only the pnpm catalog entry. Never applied unless passed. | No |
--verbose | Print full bootstrap error output on failure (alias: set ${ENV_VARS.UPGRADE_DEBUG}=1) | No |