Skip to content

Lodestar 1.2.6 — a stuck project can save again

Choose a tag to compare

@github-actions github-actions released this 14 Aug 20:32
· 23 commits to main since this release
Immutable release. Only release title and notes can be modified.
aacc471

Lodestar 1.2.6

A project could permanently lose the ability to save continuity, and the command to save
one was refused unless typed in exactly one spelling. This release fixes both.

Lodestar 1.2.6

npm install --global lodestar-agent-context@1.2.6
lodestar start --cwd .

A delivered baton kept guarding the door

A recovery record has two states. pending means a baton is waiting for the next
session. claimed means a successor has already read it.

handoff now refused to write when a recovery existed and the caller was not its
claimant. That is right for pending — overwriting an undelivered baton destroys
someone else's work — but wrong for claimed, where the content has already been
handed over and nothing remains to protect.

The consequence was permanent. A claimed recovery cannot be re-claimed by anyone but
its claimant, so if that session never saved a baton of its own, every later session
got:

handoff_conflict: A pending or claimed project recovery is owned by another session.

There is no handoff clear, and handoff disarm only retires a lane. The project was
stuck with no way out short of editing the registry by hand.

This is reachable in ordinary use. Resume a session, let Lodestar hand you the baton,
then close the host without saving a new one — that project is now wedged.

What changed

handoff now refuses in exactly one case: a pending recovery written by a
different session. Nothing else blocks a save.

pending,  another session   refused   an undelivered baton is someone else's work
pending,  same session      allowed   supersedes your own draft, still idempotent
claimed,  any session       allowed   the content was already delivered

A pending baton never wedges anything, because the next session in the project claims
it on startup and can then save. Removing the claimed case removes the only state that
had no exit.

The refusal message now says unclaimed rather than pending or claimed, and carries
the recovery id, its generation, and what to do next.

One phrase, one spelling

Writing a baton requires the user to say it, not the agent. That gate compared the whole
prompt against one literal string, so every ordinary way of typing a command was refused:

handoff now        authorized
$handoff now       refused
/handoff now       refused
Handoff Now        refused
handoff now.       refused
lodestar handoff now   refused

Agents prefix sigils by habit. A refusal here reads as "you are not allowed to do this",
so the agent stops asking and drives the raw CLI instead — routing around the very gate
that was supposed to hold.

The security property was never the spelling. It is that the whole prompt is the
command and nothing else
, which is what keeps a passing mention from authorizing a
write. Case, spacing, a leading sigil, and a trailing period cannot change intent, so
they no longer matter. Prose still does not authorize:

handoff now please         unauthorized
please handoff now         unauthorized
don't handoff now          unauthorized
handoff now and then disarm    unauthorized

If a project is already stuck

Nothing to repair. Upgrade and save a baton as usual — the stale claim no longer
blocks it, and the next save opens a fresh generation. Earlier packets are kept.

Upgrading

Schema unchanged since 1.2.0. Refresh the plugin and restart the host so the running
process loads it:

npm install --global lodestar-agent-context@1.2.6
codex plugin add lodestar@personal

Requires Node.js 24.15.0 or newer.