You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
lever version now appends build provenance to the release string when the
binary carries it: the commit it was built from (short) plus -dirty for an
uncommitted tree (any go build / make install from a git checkout), or the
module version for a go install …@vX build. A make-install binary that lags
its source no longer hides behind the bare hardcoded version string.
lever init --adopt: record owner-customized scaffolds (the operator/agent
SKILL.md files and the whole tree-root CLAUDE.md) as an accepted baseline in .lever-state/skills-adopted.json. Doctor's "operator skills" check and lever init --check then treat the adopted content as OK, and a plain lever init leaves it alone (including not appending the CLAUDE.md block).
Previously a customized scaffold read skipped-modified forever. Adoption
is deliberately a recorded baseline rather than a mute: the scaffolds live
inside the agent-writable tree, so the check doubles as tamper detection —
any change PAST the adopted baseline fails doctor as "modified since
adoption", and the baseline itself lives host-side where an agent cannot
re-bless its own edits. Only genuine customizations qualify: framework-
current files and stale-but-unmodified scaffolds (plain-init refresh
territory) never get a record. lever init --force still restores the
framework content — for CLAUDE.md, by re-ensuring the marker block in place
— and clears the now-stale adoption record.
Fixed
lever up no longer needs a second run to clear the first-boot start-manager race on a cold VM. The scion workstation daemon registers its
runtime broker asynchronously after its Hub API comes up, so the first
create/resume could act before the broker was ready — failing the apply (on a
cold VM as a hub "context deadline exceeded") so only a second up
reconciled. start-manager now waits for the runtime broker to be registered
and online (via scion hub brokers) before acting, closing the window at the
source; the wait is fail-soft, so it can never fail the bring-up on its own.
As a backstop, the transient-broker retry also now treats a hub "deadline
exceeded" as the same race, and the initial observe scion list rides that
bounded, ctx-checked retry instead of failing on the first blip.
lever destroy now clears the persisted controller PAT
(.lever-state/controller.pat). The PAT is minted against the hub DB that
lives inside the jail, so destroying the machine leaves it stale; the next lever up reused it (ensureControllerPAT no-ops when a PAT is already
persisted) and the new hub's fresh DB rejected it, failing the readiness
probe with "authentication failed" until the file was removed by hand. Only
the current-instance teardown (no --machine) clears it, alongside the
broker stop and staged-ticket cleanup it already does.
lever apply no longer re-imports every agent image into the jail on each
run. The load-image step now first compares the jail's podman image ID
against the host docker image ID and skips the multi-GB docker save | podman load re-stream when they match (the config digest is stable across
save/load, so equal IDs mean the exact bytes are already present). The check
is fail-open — any uncertainty (a not-yet-loaded or rebuilt image, an inspect
failure) falls through to a load, so it can never wrongly skip and leave a
stale image. This matters most under the first-boot retry loop, where any
step failing re-runs the entire plan: previously each retry re-streamed
every image; now unchanged images are near-no-ops. After a load, the step also
prunes dangling (untagged, unreferenced) jail images — so a rebuilt image,
whose old copy the load leaves untagged, no longer ratchets the grow-only jail
disk up by a full image size (a no-op when nothing was superseded). Pruning
never touches a tagged or container-referenced image.
A tool whose broker backend carries a path (e.g. qmd's [::1]:3101/mcp) now
reaches that path exactly on the tool root, instead of a trailing-slash
variant (/mcp/) that a strict streamable-HTTP endpoint 404s. The trailing
slash was an artifact of the broker's subtree mux; qmd was the only tool with
a path-suffixed backend and so the only one that couldn't connect. Path-less
backends (every other tool) and sub-path requests are unaffected.
lever doctor's "agent certificate" check no longer cries wolf right after
a healing restart: an expired-leaf rejection logged before the current
broker started (pid-file mtime) is reported as healed rather than as an
active failure. Previously any rejection inside the 15-minute window failed
the check even when the restart that fixed it had already happened.
The broker's mTLS serving cert now self-rotates. It was minted once at
startup with the 24h leaf TTL, so a broker running longer than a day served
an expired cert and every gateway handshake failed — tools down, and the
agents' own /renew calls failed with it, so their leafs decayed too (the
only remedy was a lever stop && lever up power-cycle). The broker holds the
CA key, so it re-mints its serving cert in-process via a rotating GetCertificate source when less than 6h of validity remains; agent leafs
were already kept fresh by the 12h renew sidecar once the broker stays
reachable.
The agent's mTLS client leaf now hot-reloads on the live MCP/LLM path. Claude
Code read CLAUDE_CODE_CLIENT_CERT/_KEY once at process start and cached the
leaf for its whole lifetime, so after ~24h the boot cert expired and every
gateway call failed with tls: certificate has expired — despite the renew
sidecar rewriting a fresh leaf every 12h — until the manager was restarted. A
new lever-agent gateway sidecar now runs a loopback (127.0.0.1) reverse-proxy
that terminates plaintext from Claude and re-presents the always-current leaf
to the broker over mTLS, re-reading agent.{crt,key} per TLS handshake. Claude
no longer holds the rotating cert: boot points its MCP --transport http URLs
and ANTHROPIC_BASE_URL at the loopback gateway. The proxy caps idle broker
connections at 5m so a rotated leaf reaches the broker well before the 24h
expiry, uses FlushInterval = -1 for MCP's SSE streaming, and binds loopback
only (it holds the agent key). Boot-time discovery and llm-token calls still go
direct to the broker (the gateway isn't up during pre-start).