Skip to content

Releases: opum-ai/lore-cli

Lore CLI 0.14.1

Choose a tag to compare

@jeremy-newhouse jeremy-newhouse released this 20 Oct 13:41
85d583c

0.14.0 was tagged and never published. Tag v0.14.0 names a commit and is not moved
(LCLI-714). Its Release run — 39347496150, dispatched at that tag with publish: false,
attempt 1, head SHA 077ee53f7b167acab0fabb745fc74cbb92ab0b1e — concluded failure, so no
@opum-ai/lore* package at 0.14.0 exists on the registry and latest still reads 0.13.0.
Nothing was staged and nothing was re-run. 0.14.1 carries 0.14.0's changes, the commits
landed since the tag, and the repair below.

Fixed

  • The release gate probe installs the quest peer its lore check drives (LCLI-714,
    DEC-204 (b)). The release-gate-probe job added in LCLI-738 checks out the tree and downloads
    the qualified tarballs, but carried no way to obtain quest, so lore check failed closed
    before either arm could measure anything: the six jobs failed in their FRESH arm with
    error: the `quest` CLI is not installed or not on PATH and
    hint: install @opum-ai/quest@0.14.0. That is why run 39347496150 is red and 0.14.0 was
    never staged. The job now calls .github/actions/setup-quest, the same composite action the
    tracker, docs-gate and build jobs use, with the version derived from CLAUDE.md's
    managed block and the source ref pinned alongside ci.yml's QUEST_SOURCE_REF. The pin and
    the declaration move in lockstep, asserted by test/release-workflow.test.ts rather than by
    a comment.

Lore CLI 0.13.0

Choose a tag to compare

@jeremy-newhouse jeremy-newhouse released this 07 Oct 16:29
838ba15

Added

  • The opum-lore plugin now ships the Lore pane (LCLI-664; OPAG-1075) — a Claude Code
    hooks module ("mod") that puts the repository's documentation bundle in a pane. It browses
    the bundle's concepts by type from lore query and opens one rendered as Markdown or raw
    with its frontmatter; internal link clicks navigate in the pane with a Back history; search
    takes free text with type and tag filters, and a refs toggle adds --across-refs to read
    open pull requests; New creates a document through lore new and opens whatever id comes
    back, so the pane mints no ids of its own and cannot collide with documents created on a
    branch; a fields form rewrites the open document's frontmatter, then validates the written
    file with lore validate, keeping the previous bytes and showing lore's own message when
    validation fails; rename, supersede, link and unlink run the matching lore command and
    then lore sync. Everything goes through the CLI rather than a reimplementation, so link
    repointing on rename and managed task blocks stay lore's own behaviour. Body editing is the
    fields form, a lightweight inline editor for the body (text, cursor, insert/delete and
    undo/redo in a Client region, drawn with the engine's own elements and saving through the
    same lore validate path), an Open in editor action that hands the file to the person's
    own $EDITOR through the session's shell escape (the inline editor is offered only on the
    terminal and desktop surfaces, and the pane points at this action instead wherever the surface
    has no editor region — the VS Code surface has none, and the mobile surface is told the pane
    needs the terminal or desktop), and an Ask Claude… button that fills
    the prompt box and sends nothing itself, so Claude's normal permissions and this
    repository's documentation rules apply; Markdown, diff and syntax highlighting use the
    engine's own Markdown and Code elements rather than a bundled renderer, and the editing
    model is vendored @codemirror/state with its license and provenance recorded beside it
    (a hooks module can import only its own files and claude-code). The
    pane ships in the plugin cut from this repository's release tag, so a plugin user gets the
    pane matching the CLI version they installed; mods need Claude Code 2.1.287 or later. Its
    component reference is Lore pane mod.
    The module's tests run under the Claude Code engine against a stage of exactly what the
    plugin ships — bun run test:mod (scripts/mod-test.mjs) — and CI runs them in a
    mod gate (opum-lore plugin) job. That harness fails rather than skipping when it cannot
    test anything (no claude, one older than 2.1.287, a shipped directory absent, a stage with
    no module), and it reports its typecheck as NOT TYPECHECKED rather than implying one it
    could not run: the typecheck is machine-local against the engine's own declaration and CI
    cannot assert it. Covered by the module's tests: browse, read, Back, Raw, search and its refs
    toggle, New, the fields form with its validation-failure path, the inline editor (a key,
    the cursor cell, undo, Save through lore validate, and the rejected-save restore), and the
    rename/lore sync argv. Not covered, and so not claimed: supersede, link, unlink, Ask
    Claude…, Open in editor, and the uncommitted-changes landing strip.

  • The Lore pane gains a full-screen toggle and an entry point of its own (LCLI-666, LCLI-667,
    LCLI-668) — opum-doc's "add full screen mode and a toggle for it" and "'lore-pane' to just
    'lore'". z inside the pane flips it between its normal size and the largest the surface
    allows, and the dashboard tool's full argument opens it full screen directly; a second press,
    or full again, returns it to normal, and the choice is remembered across sessions. In full
    mode the pane draws the outline, or the search results, beside the open document once it has at
    least 120 body columns, and keeps its stacked layout below that. The pane's command name moved
    /lore-pane → /lore in the design and then off the slash surface entirely: the engine refuses
    a mod command named lore, which the plugin's own lore skill owns, and registering one skips
    the whole session.start hook — so the pane ships no slash command of its own, and its only
    entry point is the module's mcp__opum-lore__dashboard tool, which the lore skill routes to.
    /lore dashboard (and the plain words "lore dashboard") opens the pane as it stands;
    dashboard full, dashboard <doc-id> and dashboard search <text> map to the tool's full,
    doc and query inputs, and every argument that does not start with dashboard goes to the
    CLI as before. The tool never takes the keyboard — a Tab or a click gives the pane the keys.

Changed

  • The pinned Bun moves back to 1.3.14, and engines.bun narrows to >=1.3.14 (LCLI-686;
    DEC-163 (8), opum-doc, 2026-10-06). The LCLI-660 two-window measurement found the Linux epoll
    runtime race on the 1.4.2 pin (10/20 and 17/20 CI runs) and never on 1.3.14 (0/20 in both
    windows), and that race is what failed the required ubuntu lint · typecheck · test leg even on
    diffs that cannot reach a test. The 1.4.2 floor existed for the LCLI-648 parser panic, which
    DEC-163 (8) works around by avoiding the construct — lore's source carries no Bun.Transpiler
    and no top-level declare binding, so the panic cannot reach shipped code. The floor test that
    exercises the repro now skips itself on 1.3.14 and names LCLI-648, re-arming if the pin moves
    forward again. Breaking for consumers who read engines.bun, as LCLI-648's move was.

  • The lore agent context pack footer now counts the eligible deck, and a
    zero-score omission carries its own reason
    (LCLI-680; ODOC-437 slice 1, AC1).
    total, shown and truncated are computed over the candidates that remain
    after the zero-score exclusion — selection step 4 of the opum-doc task-context
    contract, docs/specs/opum-task-context-and-evidence-contract.md, which drops a
    candidate scoring zero once the task's own terms rank the deck. Such an exclusion
    happens before any budget is spent, so it is not a budget cut and no longer sets
    truncated: a pack that holds every eligible candidate reports truncated: false however many zero-score candidates it excluded (measured on this
    repository's own implementation profile: the LCLI-289 pack now reads
    198 of 198; truncated: no where it previously counted the full declared deck;
    the count moved from 197 to 198 because this change's own documentation edits
    grew the declared deck).
    The exclusion stays visible — the catalog reports a source all of whose
    candidates were excluded this way with the new reason omitted-by-relevance,
    distinct from omitted-by-budget, so a zero-relevance exclusion is never
    reported as a budget cut. Contract-visible for consumers of
    agent.context.export: the meaning of the footer's total/truncated changes
    as described, so that envelope's schemaVersion is bumped 2 → 3 under
    cli-contract §7.1 — a meaning change to existing fields, scoped to that kind.
    The agent.workflow.projection envelope is bumped 1 → 2 by the same change,
    since it embeds a pack compiled by the same selection code, so total, shown,
    selectedCount, topScore and reason move inside it too (lore help --json
    now reports kindSchemaVersions: {"agent.context.export": 3, "agent.workflow.projection": 2}); its embedded pack stays hit-free. A source
    dropped whole by relevance now reads a different reason than one dropped by
    budget; the new reason value is additive under §7.1, as the workspace-only
    reasons were.

Fixed

  • The capacity measurement now stands for the largest pack a real task can compile (LCLI-662;
    DEC-98 B, ADR-0025).
    lore check's agent-profile-capacity measurement previously excluded the bundle-wide query
    section a real lore agent context pack renders, and rendered its score placeholders one character
    wide where real scores render seven to ten — so a green check could certify a profile whose real
    task pack dropped a declared source by budget (measured: a declared set green at 2957 tokens
    against a 2982-token budget, omitted-by-budget on the pack; and hit-free packs up to ~500 tokens
    larger than the measurement on this repository's own profiles). The measurement now reserves the
    query section's worst case, task-independently, and renders score annotations at full width, so a
    budget that satisfies it cannot start dropping declared evidence on a task — up to the one residual
    ADR-0025 records and measures: the pack header renders the task text verbatim, so a task much
    longer than the measurement's fixed stand-in can still consume the margin. The finding is still
    computed from the declaration and the bundle, never from a task. This ships as a warning for
    one release before LCLI-646 flips it to an error (DEC-11).
  • The Lore pane's full mode now follows the engine's own sizing, and its answers report what
    actually drew
    (LCLI-675; DEC-154). The pane asked for rows - 6 inline, where the engine caps
    an inline pane at rows - 11, so a full request could never be granted as asked; its docked
    request was computed from the conversation column — a shrink request that a kept
    pluginPanes.dockColumns then beat anyway — and the dashboard tool answered with the size it
    asked for rather than the size that drew. The module now asks rows - 11 inline and recovers
    the terminal width in the dock from one render (transcript + the drawn body + the divider, less
    the engine's 24-column floor), asks once per toggle rather th...
Read more

Lore CLI 0.12.0

Choose a tag to compare

@jeremy-newhouse jeremy-newhouse released this 30 Sep 18:11
739f2b4

Added

  • lore query --across-refs — read the bundle across refs, read-only (LCLI-652; ODOC-330 /
    DEC-40, paired with quest-cli QCLI-417). A document added on an open pull request is invisible
    until it merges, because a checkout sees only its own bundle; this answers for the repository.
    Bare, the population is origin/dev plus every open pull request into dev, discovered
    through gh; given one or more ref names, it is exactly those refs, resolved locally with no
    forge and no fetch. Every hit gains refProvenance {ref, pullRequest, sha} — a separate key
    from --workspace's provenance, which carries an unrelated workspace identity — and every
    answer reports coverage {complete, population, discoveredAt, refsRead[], refsUnreadable[]}
    as an envelope key between data and principal, in the shape agreed byte-for-byte with
    quest-cli. Conflicting copies of one id are shown side by side, never merged: an id on
    origin/dev always emits dev's row, another ref's copy emits a row only when its bytes differ,
    and an id absent from dev emits one row per ref carrying it. Nothing is written — other refs
    are read with a destination-less git fetch (objects only) and git archive into a temporary
    directory, and lore sync refuses the flag, since a branch's managed blocks regenerate only
    from that branch's own records. An incomplete read is a drift error at exit 6 naming the
    unreadable refs and carrying the coverage object in the error's input, with nothing on
    stdout; --allow-partial answers at exit 0 with complete: false instead. With no gh on
    PATH, or an origin that is not GitHub, the run degrades to population: "dev-only" the same
    way — incomplete coverage, never an uncaught failure.

Changed (breaking)

  • The pinned Bun moved from 1.3.14 to 1.4.2 (LCLI-648, pair with quest-cli QCLI-411).
    Marked breaking because engines.bun moves with it to >=1.4.2, so the declared support floor
    narrows: a consumer running the package from source on Bun 1.3.x is now outside it. Nothing
    else about the surface changes.
    1.3.14 mis-parses a TS contextual keyword — declare, type, abstract, namespace,
    module, global, interface — that starts a larger expression, desynchronising the parser's
    scope tracking and panicking the runtime: oven-sh/bun#31239's repro exits 133 with no output
    on 1.3.14 and exits 0 on 1.4.2, and test/bun-declare-binding.test.ts pins that on the
    pinned runtime. Two upstream behaviour changes ride along. Bun.Glob now descends
    into dot-directories by default — .github/workflows/* returns 0 matches on 1.3.14 and 4 on
    1.4.2 (dot: true returned 4 on both) — which changes what a dotted lore replace --in
    pattern matches, previously nothing. And Bun.TOML.parse rejects an imprecise bare integer
    literal that 1.3.14 silently rounded; both runtimes still surface a stable validation error
    naming the config file, and test/config.test.ts covers each shape.

  • lore now refuses to drive a quest that is not its exact pair version (LCLI-650; DEC-31
    adopting the opum-doc ADR lock-lore-and-quest-to-their-exact-pair-version-at-runtime). The two
    CLIs carry one version number in every release (constitution Article 3 clause 1), so a correct
    install never notices: the check compares the full version string once, at the capability gate
    every quest-backed command passes before its first quest spawn. A mismatch fails — exit 6,
    validation, with a message naming both installed versions and the side to upgrade — rather than
    warning. Marked breaking because a mixed pair that used to work (lore X against quest Y) now
    refuses until the older side is upgraded; that is the intended cost, and the message names it.

  • lore init detects a tracker, offers, and instructs — it never installs, initializes, or migrates
    one for you
    (LCLI-656; DEC-57, adopting ADR-0024). Every path that used to act on the operator's
    behalf now stops with the exact commands instead. A quest selection with no quest on PATH
    stops with the install pinned to lore's own exact version (npm install -g @opum-ai/quest@<lore's version>) plus quest init (dropped when the repository already has a
    Quest workspace) and the rerun; a backlog selection likewise names backlog.md and its floor.
    A repository holding a Backlog project is offered the migration commands rather than migrated
    from the wizard, and no TTY means the same stop rather than an assumed "no". Marked breaking
    because three previously-advisory cases are now stops: --tracker quest or --tracker backlog
    with the CLI missing or the project uninitialized used to warn and persist a selection (exit 0)
    and now stop with the instructions (exit 3/6), writing nothing at all — the stop precedes the
    scaffold, so neither the selection nor the bundle lands until the backend can serve it. --install-tracker and --no-install-tracker are accepted for one release as no-ops that
    print a deprecation note — they install nothing, on any path, and together remain a usage error.
    The wizard's post-migration backlog/ removal offer is gone with the wizard's migration arm
    (the flag path's --remove-backlog/--no-remove-backlog is unchanged), --no-tracker remains the
    documented opt-out, and a bare non-interactive lore init still pins the default backend and
    probes nothing (LORE-260). The remedy names lore's own exact quest version, never latest, so the
    onboarding message and the runtime pair-lock refusal are one sentence.

Changed

  • A profile anchor on a heading nested inside a blockquote or a list item resolves, instead of
    crashing lore agent context
    (LCLI-647; DEC-22 option A). The renderer read top-level headings
    only while the validator's walk saw every node, so such a profile validated and then exited 1
    with zero bytes of stdout; both now read one shared heading enumeration. A nested section's region
    stops at its container and its breadcrumb names its nested ancestors; an anchor that matches no
    heading is a validation refusal (exit 6) with a remedy, never an uncaught crash. Where a
    duplicate heading takes a slug (a quoted # Overview beside a top-level ## Overview), an anchor
    on that slug now resolves to the heading the slugger assigns it — the meaning the validator and
    GitHub's own anchors already used. That re-points one case a profile could have relied on: an
    anchor of #overview where a quoted # Overview took the slug resolves to the QUOTED heading,
    not the top-level one the pre-fix renderer picked; anchor #overview-1 for the top-level heading.
    Classified ### Changed rather than breaking: the pack item's target changes, but nothing is
    refused that worked before, and the pre-fix target was the violation of this repository's own
    retrieval spec.
  • A RESUMED promote-latest run now refuses when any package's current latest is newer than
    --version
    (LCLI-638, twin of quest-cli QCLI-405). The LCLI-631 gate validated the record a
    FRESH run was about to write, and a resume reuses the record the first run wrote instead — so
    nothing compared the registry as it reads NOW with --version, and a run resumed after something
    else moved latest ahead would move it backwards, the move the ADR refuses. planPromotion now
    makes the same numeric comparison on the resume path, before any write, naming the package and
    both versions; a package already at --version stays accepted, which is the partial state a
    resume exists for. The comparison is by the release a live value leads with, so a registry
    latest of 5.7.0-rc.1 counts as newer than 5.6.7 and refuses, while 5.6.7-rc.1 or
    5.6.7+build.7 is not newer than 5.6.7 and still resumes. On a fresh run, a package whose
    current latest is not a plain X.Y.Z now gets a headline in the registry's own terms before
    validateRecord's "recorded prior latest ...", which named a value nothing had recorded yet.
  • Every release script now runs its CLI when it is invoked through a symlinked path (LCLI-637,
    twin of quest-cli QCLI-404). Six scripts guard main() — launcher-equivalence, pair-receipt,
    promote-latest, version-parity, github-release and check-breaking-bump — and all six
    compared resolve(process.argv[1]) with fileURLToPath(import.meta.url). That is false through
    any symlinked path, because resolve() never follows a link while Node resolves import.meta.url
    to the module's real one; the macOS tmpdir (/var -> /private/var) trips it with no symlink of
    anyone's own. The failure was silent in the worst way: the process exited 0 having done nothing,
    so a release gate reported success for work it never did. All six now call one shared
    realpath-based isMain() in scripts/is-main.mjs, and test/lcli637-is-main-symlink.test.ts
    invokes each of them through a real symlink and fails against the old guard. Measured before:
    node scripts/version-parity.mjs --help exits 2 with 52 bytes of usage, the same file through a
    symlinked directory exits 0 with 0 bytes. After: both exit 2 with byte-identical output.
    check-breaking-bump.mjs is in the list because re-measuring the inventory repo-wide found it,
    not the four sites the record named.
  • provenance-post's not-published warning now leads with the cause that run's publish job
    allows
    (LCLI-635, LCLI-628's reviewer finding F4). A package this release should have published
    but the registry does not list has two explanations — a publish that stopped partway, or the
    registry read API lagging a publish that succeeded (LCLI-460). The warning led with the partial
    publish either way, so on a run whose publish job was green it named a cause that could not be
    true and prescribed "Re-run failed jobs" for bytes that were already on the registry. release.yml
    now passes `need...
Read more

Lore CLI 0.11.0

Choose a tag to compare

@jeremy-newhouse jeremy-newhouse released this 27 Sep 05:04
bb225f1

Upgrade notice: schema drift on every repository that commits .lore/schemas/

  • This release adds two built-in document types, so the built-in profile's digest changes and
    every committed .lore/schemas/ goes stale at once
    (LCLI-599, OPAG-425 R10). After upgrading,
    lore check exits 6 with schema-drift findings until you run lore schema export and
    commit the regenerated .lore/schemas/*.json. That covers the re-stamped existing schemas plus
    the new constitution.schema.json and constants.schema.json. Nothing else is needed; do not
    hand-edit the stamps. Measured by ref on 2026-09-26: 10 of 10 fleet repositories commit
    .lore/schemas/ (nine hold the eight pre-Constitution schemas), so every one of them needs this
    step in the same change that bumps its lore pin.
  • The lore agents managed block now depends on the lore version when a Constitution or
    Constants document exists
    (LCLI-597). A repository that adds either document and regenerates
    its block with this release will fail lore agents --check under an older lore, and an older
    lore would strip the new lines again. Upgrade every CI job that runs lore agents --check in
    the same change. A repository with neither document is unaffected: its block is byte-identical.

Added

  • Built-in Constitution document type (LCLI-595, OPAG-425 R1-R4, R9). At most one per bundle.
    It carries required version, ratified, last_amended and amendment_authority, and the
    sections Principles, Governance and Amendment log. ### P<n>. <Name> principles need an RFC
    2119 keyword, Rationale: and Check:. lore validate and lore check both enforce the
    shape, and lore new constitution writes a document that passes.

  • Built-in Constants document type (LCLI-596, OPAG-425 R1, R2, R5-R7, R9). A catalogue of
    named concrete values, at most one per bundle. Each ### entry is an id, cited by its heading
    anchor (the anchor drops dots: service.http-port is #servicehttp-port). lore check:

    • compares every entry whose source_of_truth names a git-tracked JSON, TOML or YAML file and
      key against that file (new rule source-of-truth);
    • warns on a link to a deprecated or retired entry (deprecated-reference);
    • fails a Constants document from which no entry was read (zero-entries-read);
    • prints the entry, comparable-source and reference counts it read (readCounts in --json).

    No finding ever prints what a source file holds. lore new constants writes a document that
    passes.

  • lore agents renders governance into its managed block (LCLI-597, OPAG-425 R8). With a
    Constitution present, the block gains its path, version and each principle's MUST/MUST NOT
    rules. With a Constants document present, it gains a read-before-you-name trigger line and
    id = value for active entries flagged hot. lore agents --check reports drift when either
    document changes. Document text is rendered inert.

  • lore agent context pins the bundle's built-in Constitution first in every pack (LCLI-609,
    OPAG-425 R8 as clarified by Amendment 4). That covers every profile's pack, an unknown profile's
    degraded pack, and the pack that lore agent project and lore agent context --contract embed.
    It carries the catalog reason constitution, and in the projection its file is listed in
    inputRevisions.

    • A profile that already references the Constitution keeps its own reference and gets no second
      copy.
    • A profile-declared Constitution type is never auto-pinned.
    • --workspace packs are unchanged.
    • The auto-pin counts toward the budget like any pin, so a Constitution the budget cannot hold
      exits 6. Narrow it to a heading in the profile instead.
    • With no built-in Constitution, every pack is byte-identical to before.
    • Additive contract effects: a new catalog reason value, and packDigest/contextDigest
      change for any bundle that has a Constitution.

Changed

  • BEHAVIOUR CHANGE: lore check now fails on the error-tier frontmatter and required-section
    findings lore validate reports, for every type
    (LCLI-606). Ships in a lore minor release.
    Until now lore check could exit 0 over a document that lore validate failed. It now exits
    6 on every such finding: a missing required section (an ADR without ## Consequences, a Story
    without ## Acceptance criteria), a missing type, a missing or mistyped field (including one
    your own .lore/profile.toml requires), and an invalid enum value (for example an OKF 0.2
    lifecycle status that is not draft, stable or deprecated). The findings keep validate's
    rule names and messages, and check judges each file exactly as validate does, with its
    repository-relative path and the docs/ root's OKF version and profile, even in a scoped
    lore check <dir>. A stray second frontmatter fence stays one finding, under the
    double-frontmatter rule check has used since 0.4.0. Before upgrading, run
    lore validate
    : its required-section findings and error-tier frontmatter findings are
    exactly what lore check will now fail on. Files without frontmatter are still skipped.
    validate's error-tier quote-safety findings, and its resource and warning-tier findings, stay
    validate-only. A tasks:-linked document with invalid frontmatter now draws an ordinary
    frontmatter finding and is left out of reconciliation. Before, it aborted the run with the
    first such error only (a thrown error on stderr, complete: false in --json). The exit code is
    still 6. The --json report's shape is unchanged: the new findings are new values of the
    existing rule field. LCLI-598 measured the ten fleet repositories on 2026-09-26 and found 1 of
    384 documents that would newly fail, since fixed. A re-measurement before merge, counting every
    error-tier finding, found 0 of 385.
  • Declaring the built-in Constants type adds owner and last_reviewed to the profile-wide
    frontmatter key order
    (LCLI-596). A document of any type that already carries owner: has it
    reordered on its next lore rewrite. Measured 2026-09-26: 0 fleet documents affected.

Fixed

  • lore unlink no longer fails when another writer removed the back-reference label first
    (LCLI-614). It removes the label only when its own read found it, and it removes every case
    variant by its stored spelling. A guarded Quest edit whose own task's labels or documentation
    changed under it is retried as a conflict, even when quest 0.10.0 reports it as a validation
    miss. lore link now guards its whole-list --doc write with --if-revision too. Conflict
    retries back off briefly, with jitter. Behaviour change: only a conflict from an edit that
    actually sent a precondition is retried. A Jira rate limit or timeout on lore unlink or a
    rename's back-reference move now fails after one attempt, where before there were up to four
    immediate attempts.
  • A Claude Code plugin row set by your administrator (managed scope) now decides, and is never
    updated
    (LCLI-604, LCLI-608; ADR ruling 28). Scope precedence is managed > local > project >
    user > synced. A managed row applies to every project, and among several managed rows a
    disabled one wins. lore agents --target claude --force never runs an update against it and
    never prints --scope managed. Installed or disabled, it reports update: not-run with a
    remedy naming the administrator's managed settings, not a command you can run.
  • The shared output sanitiser also strips bidi overrides, isolates and invisible format
    characters
    (LCLI-607): U+202A-U+202E, U+2066-U+2069, U+200B, U+2060 and U+FEFF. An RLO in a
    document title or a runtime message can no longer reorder a printed line. ZWJ, ZWNJ, LRM, RLM
    and ALM are kept, because they carry meaning in emoji and RTL, Persian and Indic text. The class
    is identical to quest's.
  • lore link no longer half-applies when Quest has no actor declared (LCLI-582). With
    LORE_QUEST_ACTOR unset, it used to write the concept's tasks: frontmatter, then fail the
    back-reference edit with exit 6, leaving a one-sided link. It now refuses before any write, so
    the exit 6 leaves the concept file byte-identical. A run that needs no back-reference edit
    (label and documentation entry already present) still succeeds without an actor. lore unlink
    applies the same check before removing tasks with back-references on. Behaviour change:
    unlinking a task whose label is already gone now needs an actor too, where before it succeeded;
    --no-back-ref skips the check.

Lore CLI 0.9.3

Choose a tag to compare

@jeremy-newhouse jeremy-newhouse released this 25 Sep 04:36
819a682

Added

  • Every plain lore agent context pack is query-augmented (LCLI-575; opum-doc ADR "Make lore
    agent context always query-augmented", ODOC-265, and its Amendment 1). A ## Bundle-wide query hits section lists up to
    three lore query hits for the task that the pack does not already quote, as id, title and
    snippet, with no bodies. In --json these are three additive fields on agent.context.export:
    queryHits, queryHitsOmitted (how many hits the token budget cut, so an empty section is never
    ambiguous between an empty corpus and a tight budget), and queryHitsSectionOmitted (set when
    the budget left no room for the section at all, a case also named on stderr). The section never
    raises the mandatory-pin floor: a --max-tokens that compiled before still compiles. With
    --workspace --repository, hits come from the selected members only. The opum-agent-workflow/v1
    projection (lore agent project, lore agent context --contract) does not carry the section:
    its embedded pack, packDigest and inputRevisions are byte-identical to 0.9.2's, so a
    document outside the profile's catalog cannot move a pinned digest (Amendment 1).
  • lore help --json lists kindSchemaVersions, the per-kind schemaVersion overrides
    (additive; cli-contract §7.1). Today it is {"agent.context.export": 2}.

Changed

  • lore agent context <unknown profile> exits 0, not 3. It degrades to the query section
    plus a warning, in the pack and on stderr, and sets profileMissing: true. This remaps an
    existing exit code, which the CLI contract treats as a contract-level change; it is recorded as
    amendment §5.6 there, citing ODOC-265 decision 2. agent show, agent project and agent context --contract are unchanged on an unknown profile.
  • BREAKING (--json): the agent.context.export envelope's schemaVersion is 2 (was 1),
    for the exit 3 → 0 remap above — settled by the ADR's Amendment 1 (opum-doc main a8bb596)
    and recorded in cli-contract §5.6. The bump is scoped to that one kind: every other envelope,
    agent.workflow.projection included, stays schemaVersion 1. A consumer pinned to 1 for
    lore agent context --json should read profileMissing where it relied on exit 3, then
    accept 2.

Fixed

  • The README quickstart runs (LCLI-571). It named a lore new spec --story option that never
    existed, and it coupled Backlog.md task ids that no fresh repository has, while lore init
    defaults the tracker to Quest. It now initializes Quest first, declares the actor Quest writes
    need, and links two tasks it creates. The install section names Quest. CI runs the quickstart
    verbatim from README.md against each freshly compiled binary, so it cannot silently break again.

Lore CLI 0.9.2

Choose a tag to compare

@jeremy-newhouse jeremy-newhouse released this 24 Sep 13:44
71f2c1e

Changed

  • Agent guidance now starts with retrieval: lore query then lore read, not browsing
    docs/index.md
    (LCLI-573, OPAG-378). A new lore instructions retrieval topic teaches
    single-repository search. The overview loop and every generated bridge (the Claude and Codex
    skills and the CLAUDE.md/AGENTS.md nudges) lead with it. On one fleet repository, measured
    across 69 of its own tracker records, a query plus one read found the documented answer in the
    top five for 51 to 68 of them, depending on how the question was worded, at a median of about
    5 KB. A cat of the whole docs tree is hundreds of KB.
  • Every bridge's topic list is derived from lore instructions, so none can fall behind
    again. The hand-kept copies listed 5 of the 7 topics.
  • The committed plugin skill (skills/lore/SKILL.md) is now generated from the same builder
    as the per-repository skill, and a test fails when it drifts. It now lists read, types and
    backlog. It also states --max-tokens as the hard ceiling LCLI-478 made it: the old text
    called it advisory. Regenerate it with bun run scripts/plugin-skill.ts --write. This file
    reaches opum-lore plugin users at the next tag.
  • The generated skills drop the Backlog/.codex "commit-side-effect preflight". It routed
    commands through a retired backlog-handover gate. What remains is accurate: lore link,
    unlink, rename and sync commit tracker files only on the Backlog backend. The sync and
    init summaries in lore help no longer say "commit backlog/" or "backlog check".
  • The overview no longer ends by pointing at docs/runbooks/agent-onboarding.md, a file most
    repositories do not have.
  • Regenerating a repository's bridges picks these up, and a repo-mode skill needs --force.
    Measured on bridges written by 0.9.0: lore agents --check exits 6. The CLAUDE.md block
    reports updated, and lore agents rewrites it. The repo-mode .claude/skills/lore/SKILL.md
    reports protected, because its bytes differ from what this release generates, so only
    lore agents --force rewrites it. Repositories on skill_source = "plugin" have no such file.

Lore CLI 0.9.1

Choose a tag to compare

@jeremy-newhouse jeremy-newhouse released this 24 Sep 04:21
1ef146b

A patch release with one fix: lore new story scaffolds into docs/stories/ again (ODOC-262).
The rollout notes under 0.9.0 still apply unchanged. This release adds no exit code, type, alias
or field, so the profile digest does not move and committed schemas stay current.

Fixed

  • lore new story scaffolds into docs/stories/ again, and still writes type: Arc
    (LCLI-570; ruling OPAG-376, recorded as opum-doc ODOC-262). 0.9.0 put both spellings in
    docs/arcs/. That broke lore's own README quickstart, which runs lore new story and then
    addresses stories/<slug>, and it broke a consumer that asserts the folder. Until 1.0.0 the
    output directory follows the spelling you typed: the Story spelling, in any case, scaffolds into
    docs/stories/, and lore new arc keeps docs/arcs/. The written type: is always the
    canonical Arc, so no new document carries the deprecated spelling. Documents 0.9.0 already wrote
    under docs/arcs/ stay where they are and keep working. Nothing migrates them, and an Arc
    validates, links and checks the same way in either directory. A custom profile whose canonical
    type is itself named Story also scaffolds into docs/stories/ again, as it did before 0.9.0.

Deprecated

  • What 1.0.0 removes with the Story alias: the Story input spelling (lore new story,
    type: Story documents, lore query --type Story), story.schema.json, and the docs/stories/
    output path that lore new story uses. From 1.0.0, lore new arc is the only spelling and
    docs/arcs/ is the only scaffold directory. Documents already under docs/stories/ are not
    moved by lore; move them with lore rename before upgrading if you want them in docs/arcs/.

Lore CLI 0.9.0

Choose a tag to compare

@jeremy-newhouse jeremy-newhouse released this 22 Sep 23:03
fd71274

The headline is LCLI-565: committed schemas now say which lore profile generated them, and
lore check gains a seventh exit code, 7 (indeterminate), for a schema it cannot attribute.

Before this release, lore check could not tell an orphaned schema it had written itself from one
it had never seen, so it advised the same prune for both. That advice is destructive, and
LCLI-546 came one git add -A away from committing its result. This release makes the difference
decidable, and it never advises deleting a file it cannot attribute.

The version is 0.9.0 rather than a patch because exit 7 is a breaking CLI-contract change under
ADR-0005. It is not chosen to match quest's number. Whether this lore and any quest release
form a qualified pair is for opum-cli-e2e to measure, and nothing here claims one. Detect a
capability by presence, never by comparing versions.

Rollout — read this before bumping your lore pin (LCLI-565)

  • Exit 7 / error_type indeterminate is a new lore check outcome, and it is a breaking
    CLI-contract change.
    A consumer that freezes the exit-code taxonomy (0 2 3 4 5 6),
    or that branches only on 6, will misread it. Exit 7 means "cannot judge this from here":
    do not auto-repair it, and do not run lore schema export or lore sync as a fix. Read
    git log on the named file. A run with both 6-class and 7-class findings exits 7
    (OPAG-373). The capability manifest's error taxonomy gains indeterminate: 7 (nine keys), and
    ADR-0005 and the CLI contract carry a dated amendment.
  • The first stamping release makes EVERY committed schema STALE (exit 6), NOT
    unattributable.
    No committed schema in any repository carries the stamp yet. An unstamped
    schema whose type still exists is reported stale, and one lore schema export re-stamps all
    of them
    . Only an unstamped schema that is also an orphan (no type owns it) reports exit 7.
    The Story -> Arc rename below adds arc.schema.json, which a pre-0.9.0 bundle lacks and which
    reports missing (exit 6). The same export writes it.
  • Fleet consumers skip 0.8.0. Move the lore pin to 0.9.0 AND run lore schema export in the
    SAME pull request.
    A pin-only PR goes red on the docs gate, because the new binary finds every
    committed schema stale. Commit the regenerated .lore/schemas/*.schema.json with the pin change
    (opum-agent OPAG-326).
  • After a legitimate type removal, the removed type's schema reports unattributable (exit 7)
    until a human deletes it.
    Removing a type changes the profile digest, so the leftover file
    carries a stamp the running binary does not recognise. lore schema export will no longer
    prune it.
    It is kept and reported instead. A legitimate removal now costs one deliberate rm.
    That is the design: a leftover file needing a deliberate rm is a much cheaper failure than
    deleting a file the tool could not attribute.
  • A future lore release that changes the digest projection or the reserved coupling fields
    moves every repository at once.
    The digest covers each type's name, slug, aliases, and
    declared fields with their requiredness, reserved coupling fields included. It covers no lore
    version, so an ordinary release does not move it. A release that adds or removes a type, alias,
    or field, or changes the projection itself (lore-profile-digest/1), takes every committed
    schema in every consuming repository stale at once. Such a release will ship its own rollout
    note. The stability contract is stated beside profileDigest in src/core/schema.ts.
  • lore schema export --json gains keptUnattributable. It lists the orphans that were kept
    because their stamp is absent or foreign. removed now lists only orphans whose stamp matches
    the running binary's own profile. Outside --json, a stderr warning names each kept file.

Provenance — read this before checking the packument

  • LCLI-482 is still open. OIDC trusted publishing still cannot authenticate for this
    repository. If 0.9.0 goes out through the manual scripts/publish-release.sh path, as 0.8.0,
    0.7.0, 0.6.2 and 0.6.1 did, it carries no provenance attestation. That is expected and is not
    evidence of tampering.

Added

  • Committed-schema generator stamp (LCLI-565, spec LCLI-563). lore schema export, and
    lore init through the same emitter, writes x-lore-generator.profileDigest into every emitted
    schema, alias files included. The value is sha256 over a documented, versioned projection of
    the compiled profile's type definitions. Editors and validators treat the key as an inert unknown
    keyword.
  • lore check exit 7, rule schema-unattributable (LCLI-565). An orphaned schema with a
    matching stamp is still orphaned (exit 6, prune advised). An orphan with a differing or absent
    stamp is unattributable (exit 7), and no prune is advised. Every schema finding now carries a
    schemaClass (missing / stale / orphaned / unattributable). The schema pass runs first,
    so a later validation throw cannot hide an unattributable schema: that throw is escalated to
    indeterminate, and the original message and error_type are kept.
  • Deprecated type aliases in profiles (LCLI-553). A [[types]] table may declare aliases. An
    alias resolves to its canonical type everywhere a type name or slug is read, and lore schema export emits a byte-identical schema file for each alias spelling. Name and slug collisions are
    rejected.

Changed

  • The built-in Story type is now Arc, and Story stays as a deprecated alias until 1.0.0
    (LCLI-554, OPAG-255). Existing type: Story documents keep working. lore new Story writes
    type: Arc, and both spellings scaffold into docs/arcs/. lore query --type Story matches
    documents of either spelling, and required-section enforcement applies to aliased documents.
    Consumers gain arc.schema.json beside a byte-identical story.schema.json.

Fixed

  • lore schema export no longer deletes a case-variant schema on a case-insensitive filesystem
    (LCLI-565). This defect predates this release. It was reproduced on APFS, and NTFS has the same
    case-insensitivity. A committed ADR.schema.json and the adr.schema.json that export writes
    are one directory entry there. Export's prune then read back the bytes it had just written,
    found them owned, and deleted the only adr schema. Prune decisions now come from a snapshot of
    the directory taken before any write. An entry whose case- and normalization-folded name matches
    a written name is never deleted. lore check had the same defect on the reporting side. It
    called the owned schema missing and advised pruning its variant. A stamped variant now stands in
    for the owned schema when the exact name is absent, and an unstamped or foreign one reports
    unattributable.
  • The generated type schema accepts alias spellings (LCLI-558). Alias resolution shipped
    without alias acceptance: a type: Story document resolved to Arc and was then rejected by
    the schema's single-value type literal, so lore link still refused it. type now accepts the
    canonical name and every alias. An aliasless type keeps its const form byte-for-byte.

Internal

  • The Windows launcher-qualification test no longer flakes on EBUSY (LCLI-564). Every
    assertion passed. The scratch-tree removal threw because Windows briefly holds a handle after
    the launcher exits. It now uses the bounded retrying remover the same file already tests.
  • Documentation: the 0.8.0 retained-snapshot upgrade note (LCLI-561), and the schema-drift
    remedy named in it (LCLI-545). See the 0.8.0 entry's "Known incompatibility" section.

Lore CLI 0.8.0

Choose a tag to compare

@jeremy-newhouse jeremy-newhouse released this 27 Sep 19:16
4d4a1bf

Released as a pair with quest 0.9.0, and the mismatched numbers are the point. "The pair"
means released and qualified together, not numbered alike. Exact-version lockstep was retired by
decision: the two CLIs have independent change sets, and a matched version string that is not a
matched contract invites callers to use the number as a compatibility check. Detect a capability
by presence, never by comparing versions.

The theme: 0.8.0 makes lore's own type vocabulary reachable, and stops lore emitting things its
own validator rejects.
Three of the fixes below are cases where the tool contradicted itself — a
scaffold its validator refused, a documented example its parser rejected, a type it suggested but
could not resolve.

Known incompatibility — added 2026-09-20, after release (LCLI-561)

This section was not in the original 0.8.0 notes. It is added here because the
incompatibility is real, already published, and a reader who hits it will look
at this release's entry first.

0.8.0 is the first version that writes the ADR-0021 relation qualifiers
(statement, version, relationOrdinal) into retained snapshot edges, in
commit dd0876dc (LCLI-540, #170). The schema they join is .strict(), so an
older lore rejects any snapshot file 0.8.0 wrote, with:

retained snapshot is malformed or unsupported

The failure is scope-wide, not per-file. One 0.8.0-written file makes
list, retain, load and delete all throw for the older binary in that
scope — including the drain path you would reach for to clear it.

The reverse direction is deliberately handled (ADR-0021 ruling 13,
isRetainedQualifierBackfill), so this is not a symmetric break. Upgrading
lore is the only complete remedy: the binary that rejects the file has already
shipped and cannot be patched retroactively.

The exposed configuration is narrower than it sounds. The store is
.lore/cache/snapshots/1, which is gitignored, so this does not travel through
your repository — it needs a store that outlives a version downgrade on one
filesystem, or a CI cache of .lore/ restored into a job with an older pin.

Full note, with the measurements and the containment steps:
Upgrade note: retained snapshots written by lore 0.8.0.

Provenance — read this before checking the packument

  • 0.8.0 ships with NO provenance attestation, and neither did 0.7.0, 0.6.2 or 0.6.1. Expected,
    not tampering. LCLI-482 remains open and unresolved: OIDC trusted publishing still cannot
    authenticate for this repository. GitHub issues immutable-format subject claims
    (repo:opum-ai@<id>/lore-cli@<id>:...) and npm's Trusted Publishing matches the classic
    repo:opum-ai/lore-cli:... form, so the exchange is refused and npm returns E404 on PUT. There is
    no repository-level opt-out — setting use_immutable_subject: false is accepted and has no
    effect. 0.8.0 therefore goes out through the manual scripts/publish-release.sh path, which
    cannot mint an attestation. Do not read this release as having fixed it.

Added

  • lore types — the type vocabulary, as data (LCLI-537). Prints the active profile, its OKF
    version and casing convention, then every declared type with its slug, its required sections and
    its full field table. The unknown-type warning now also names the valid set and offers a nearest
    match, so a typo is answerable without opening profile.toml.
  • profile.strict_types (LCLI-538). Makes an unknown type an unconditional error rather
    than a warning, for projects that do not want tolerated producer extensions. Off by default;
    existing bundles are unaffected.

Changed

  • lore check now detects committed-schema drift (LCLI-539). A .lore/schemas/*.json that no
    longer matches what the profile would generate is reported rather than silently trusted.
    • This can turn a previously-green lore check red on content you did not touch, which is
      the intended behaviour: the drift was already there and unreported. Clear it with
      lore schema export
      , then commit the regenerated .lore/schemas/*.json. Consuming
      repositories that run lore check as a required CI context pin lore by hand, so this reaches
      them only when they bump that pin deliberately — and it fires on the FIRST such bump past
      0.8.0, against schemas committed under an older lore, for every type at once (exit 6).
      Measured by opum-marketplace on 2026-09-19: all 7 of its profile schemas failed on its first
      0.8.0 CI run, and lore schema export cleared it.

Fixed

  • lore new <multi-word-type> is reachable from its own slug (LCLI-534). Attested Computation is the one multi-word built-in and it was unreachable from attested-computation:
    type resolution consulted only the lower-cased NAME, whose key contains a space — a spelling no
    shell argument can carry. lore new attested-computation "X" therefore wrote
    type: attested-computation verbatim, emitted no $schema modeline, scaffolded no runtime
    field, and lore validate degraded to an unknown-type warning while suggesting the very type
    it had failed to resolve. Type resolution now also consults each type's lower-kebab slug, in both
    resolution sites, so a slug-named type is known to every consumer rather than only to lore new.
  • lore new scaffolds a profile type's declared sections (LCLI-535). A type's sections are
    enforced by lore validate but were never written by lore new, so the tool's own
    scaffold produced a file the tool's own validator immediately rejected. Built-in types were
    unaffected only because their hand-written templates already carry theirs. A user template that
    overrides the body wholesale is deliberately outside the guarantee — removing a required heading
    from your own template is your decision, and lore validate will say so.
  • lore new --template <name>.md resolves the file you named (LCLI-536). The extension was
    appended to a name that already had one, so lore looked for feature.md.md and failed even
    though the exact file existed — and the not-found hint told you to create the doubled file,
    advice that would have made the error permanent. Both template sources now normalize identically.
  • lore export --help advertises a version the exporter accepts (LCLI-512). Help, the manifest
    and cli-surface.md all claimed --schema-version 1.0 and shipped it as a worked example while
    the exporter had moved to 1.1, so running the tool's own documented example exited 2. Every
    advertised value now derives from the constant rather than restating it, and two guards fail the
    build if a literal is reintroduced anywhere — one of which runs each advertised example.
  • lore link/lore unlink no longer clobber a concurrent tracker edit (LCLI-522). Label edits
    are read-modify-write: lore read a task's labels, decided what to remove, then wrote — and a
    competing writer landing in between made that decision stale while the write applied anyway.
    Against a tracker that supports an optimistic-concurrency precondition, lore now asserts the
    revision it read and retries the whole read-decide-write cycle, bounded, when the record moved.
    • Support is detected by presence, never by a version comparison. Passing the flag
      unconditionally would have raised lore's effective tracker floor and broken every version in
      between — an external compatibility change wearing the costume of a bug fix. Trackers without
      the concept are unaffected.
  • Retained snapshots now carry the ADR-0021 relation qualifiers (LCLI-540). edgeValue dropped
    statement, version and relationOrdinal — the three fields ProjectionEdgeRecord declares
    under the comment "carried verbatim so an indexed read is as precise as a direct one" — so the
    projection carried them and the retained snapshot did not. The consequence was that lore changed
    could never report a relation re-pin, and lore provenance could not recover which
    claim_version was cited at a past snapshot, which is the question ADR-0021 exists to answer.
    The three fields are now optional members of the retained edge value and the format version
    stays lore-retained-snapshot/1
    : every snapshot written before this release still validates.
    lore-retained-snapshot/2 was considered and deliberately NOT taken, so that existing snapshots
    keep validating; the qualifiers are additive and optional precisely to make that possible.
  • lore snapshot retain no longer reports a corrupt cache when only Lore's serializer changed.
    A snapshot key derives from the source projection stream rather than from the retained bytes, so
    re-retaining a commit you had already retained before upgrading produced the same key over
    different bytes and raised "retained snapshot key refers to different bytes". That was a false
    report — nothing of yours had changed. The upgrade difference is now recognised and the retain
    succeeds. It is recognised narrowly: a qualifier whose value changed, a qualifier that
    disappeared, and any difference outside those three fields all still raise the original error.

Internal — the release's own gates

  • docker/e2e/selftest.sh stays a gate as it grows (LCLI-533). A failing assertion appended
    below its reporting line ran, printed, was never counted, and left the script exiting 0 — in a
    required CI step whose entire purpose is that a gate must be observed failing rather than
    assumed to work. The conditional-exit idiom at the tail is replaced by an exit handler, which
    observes the true final state no matter where a future case is added. A trailing check would not
    have been enough: it only ever sees cases inserted above itself, and appending at the end of the
    file is exactly how this arrives.

Upgrade notes — things that will look li...

Read more

Lore CLI 0.7.0

Choose a tag to compare

@jeremy-newhouse jeremy-newhouse released this 15 Sep 12:33
5c437eb

Quest ships 0.7.0 alongside this release, continuing the lockstep pairing. The release's theme:
0.7.0 makes the graph and the contract legible to an agent, not just to a reader — anything an
agent parses must be able to express what it does not currently say.

Provenance — read this before checking the packument

  • 0.7.0 ships with NO provenance attestation, and neither did 0.6.2 or 0.6.1. This is expected
    and is not tampering. OIDC trusted publishing still cannot authenticate for this repository:
    GitHub issues immutable-format subject claims (repo:opum-ai@<id>/lore-cli@<id>:...) and npm's
    Trusted Publishing matches the classic repo:opum-ai/lore-cli:... form, so the token exchange is
    refused and npm returns E404 on PUT. There is no repository-level opt-out — setting
    use_immutable_subject: false is accepted and has no effect. 0.7.0 therefore goes out through the
    manual scripts/publish-release.sh path, and a manual publish cannot mint an attestation.
    LCLI-482 is open and unresolved; do not read this release as having fixed it, and do not read
    the absent attestation as evidence the tarballs were altered.
  • Every version published before 2026-09-10 carries a provenance link that can never resolve.
    Unchanged from 0.6.2's entry and repeated because it is the other fact most likely to be misread:
    the repository was deleted and recreated that day, destroying the commits those attestations pin.
    The tarballs, checksums and signatures are intact and correctly signed; only the commit the
    provenance names stopped existing, and npm forbids republishing a version, so this cannot be
    repaired. A destroyed SHA still resolves in a local clone's loose objects, so git cat-file
    wrongly reports it healthy — the live GitHub API is the only valid check (LCLI-481,
    docs/runbooks/release-publishing.md).

Added

  • lore read <id> — one concept, exactly as authored (LCLI-478). Its frontmatter mapping and
    full body, verbatim: no assembly, no neighborhood, no ranking, and no budget flag at all, so
    there is no configuration under which it returns less than the whole concept. Plain output is one
    header line, a blank line, then the body, so lore read <id> | tail -n +3 recovers the body
    byte-for-byte.
    • A separate operation from lore context rather than a flag on it. context assembles and
      is lossy by design; collapsing a bounded read and an exact read into one operation makes the
      caller who needs fidelity and the caller who needs cheapness share a code path, and one of them
      loses.
    • It reports no backend (LCLI-499), and that absence is deliberate: an exact read is always a
      direct filesystem load, so there is no backend choice to report.

Changed

  • lore context --max-tokens is now a hard ceiling, not an advisory label (LCLI-478). The
    emitted pack's tokenEstimate never exceeds a supplied budget. Previously an oversized target was
    emitted in full and merely flagged truncated — the caller asked for a guarantee and received a
    suggestion, with no way to tell which they had got.

    • To stay within the budget, context drops neighbors nearest-first and then, only if the target
      still does not fit, the target's own body. Omitting the flag applies no cap at all
      (LCLI-203), which is unchanged; what changed is what happens when it is supplied.
    • Nothing is dropped silently. data.omitted carries { records, fields } — dropped
      neighbor ids in the order they would have been included, and any field the budget removed.
      Both are present even when nothing was dropped, as empty arrays: if the marker appeared only
      on a trimmed pack, its absence would be ambiguous between "nothing was dropped" and "a version
      that does not report omission", and a consumer would have to diff against a full fetch to tell.
      With no --max-tokens the key is absent entirely, which is a different and unambiguous
      statement.
    • A budget too small to hold even the target's identity is refused with exit 6 naming the
      required figure, matching lore agent context's existing refusal for the same situation, rather
      than answered with something unusable.
    • target.body is now optional in context.export, and the plain renderer prints an explicit
      notice in its place pointing at lore read. The former "over budget" footer is gone: the state
      it described cannot occur any more, and a line that can never render reads as a guarantee that
      something still checks.
    • Is this a schemaVersion bump? Deliberately no — and the reasoning is recorded here rather
      than only the verdict.
      cli-contract §7.1 makes removing
      an existing field a breaking change, and a budgeted pack can now omit target.body, which
      0.6.2 always emitted — an oversized target went out in full, merely flagged truncated. It is
      scoped as non-breaking for two reasons: the field is absent only when the caller supplies
      --max-tokens
      and so opts into a bound, never on an unbudgeted call; and data.omitted.fields
      names every field the budget removed and is present even when empty, so absence is always
      positively reported rather than inferred. A consumer pinning schemaVersion: 1 that reads
      target.body unconditionally on a budgeted call must read omitted.fields instead.
      Written down because a version signal that stays still is a claim, and an unstated claim is
      indistinguishable from an oversight — the same principle this release applies everywhere else:
      anything an agent parses must be able to express what it does not currently say.
    • Documentation reconciled rather than left contradictory: ADR-0015's "--max-tokens is a
      guardrail, not a guarantee" now says what is actually approximate — the chars/4 unit, not the
      enforcement — and records that the previous wording described the defect. The agent-profile spec
      no longer points at lore context --depth 0 as the way to inspect an omitted source, because a
      depth-0 pack is budgeted too and may drop the very body the agent is trying to read.
    • Shares the contract quest-cli implements for quest task view (lore DEC-2 / quest DEC-3):
      projection opt-in and additive, a supplied bound enforced, omission always reported including
      the zero case. The unit and spelling differ because the substrates do — quest bounds by record
      count, lore by tokens across an assembled pack.
  • lore graph, query, context, path and impact now name the retrieval backend that served
    the request
    (LCLI-499). Their --json data carries backend: "indexed" or "reference".
    This is a new capability, not a restoration — no version of lore has ever exposed a positive
    backend signal, confirmed by opum-cli-e2e reading retrieval.ts, workspace-retrieval.ts and all
    five command files and verifying empirically against 0.6.2.

    • Present on every successful response, never only on a degraded one. A marker that appeared
      only when something went wrong would have an absence ambiguous between "the good case" and "a
      version that does not report this". The existing stderr advisory has exactly that defect: the
      reference backend is reached by more than one route and at least one of them prints nothing, so
      empty stderr is consistent with both "indexed ran" and "fell back silently". A partial signal
      invites the inference that it is total.
    • Why it matters now. LCLI-497 disabled the indexed backend outright on any Quest-backed
      workspace with a prerequisite, and could only be found by accident, because nothing a consumer
      can read said which path ran. Fixing that without this leaves the class undetectable.
    • Added at the envelope layer, so core/query, core/graph, core/context and core/traversal
      stay storage-neutral: which backend answered is a fact about the load, not about the result.
      The --json envelope is versioned additively (cli-contract §7), so no schemaVersion moves, and
      plain/pretty rendering is unchanged.
    • Backend parity comparisons must now exclude one field and assert it separately — the two
      backends are required to agree on the answer and to disagree about backend. lore's own
      indexed/reference conformance suite and the ladybug benchmark's parity gate were updated to do
      exactly that, which makes them stronger: they now check that each backend names itself, which
      byte equality never could.
  • Typed authored relationships, and claim state as its own axis (LCLI-477,
    ADR-0021). Until now a bundle had
    exactly one way to record that one document depends on, contradicts, or competes with another —
    an ordinary markdown link, which reaches the graph as link alongside every "see also" aside. An
    argument recorded that way is legible to a reader and invisible to lore graph, lore path and
    lore impact, which are the three commands anyone would use to ask what a change breaks.

    • relations is a new reserved frontmatter list. Each entry carries a kind and a target,
      plus optional statement and version qualifiers that make the reference precise: which
      statement, at which version. kind is one of requires, alternative, refutes,
      supersedes, superseded_by — the last two being the existing reserved coupling fields under a
      second, more precise spelling, producing the same edge kind so a reader never has to know which
      the author used.
    • claim_outcome, claim_evidence_level, claim_version are a third axis beside the two
      ADR-0019 separated. Lore never derives them from status, from lore_task_status, or from each
      other, and never writes them itself. supported is deliberately not proved and checked is
      deliberatel...
Read more