Repository navigation
Releases: opum-ai/lore-cli
Release list
Lore CLI 0.14.1
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
questpeer itslore checkdrives (LCLI-714,
DEC-204 (b)). Therelease-gate-probejob added in LCLI-738 checks out the tree and downloads
the qualified tarballs, but carried no way to obtainquest, solore checkfailed 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 PATHand
hint: install @opum-ai/quest@0.14.0. That is why run39347496150is red and0.14.0was
never staged. The job now calls.github/actions/setup-quest, the same composite action the
tracker,docs-gateandbuildjobs use, with the version derived fromCLAUDE.md's
managed block and the source ref pinned alongsideci.yml'sQUEST_SOURCE_REF. The pin and
the declaration move in lockstep, asserted bytest/release-workflow.test.tsrather than by
a comment.
Lore CLI 0.13.0
Added
-
The
opum-loreplugin 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 fromlore queryand 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-refsto read
open pull requests; New creates a document throughlore newand 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 withlore validate, keeping the previous bytes and showing lore's own message when
validation fails; rename, supersede, link and unlink run the matchinglorecommand and
thenlore 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 aClientregion, drawn with the engine's own elements and saving through the
samelore validatepath), an Open in editor action that hands the file to the person's
own$EDITORthrough 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 ownMarkdownandCodeelements rather than a bundled renderer, and the editing
model is vendored@codemirror/statewith its license and provenance recorded beside it
(a hooks module can import only its own files andclaude-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 (noclaude, 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 throughlore validate, and the rejected-save restore), and the
rename/lore syncargv. 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'".zinside the pane flips it between its normal size and the largest the surface
allows, and the dashboard tool'sfullargument opens it full screen directly; a second press,
orfullagain, 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→/lorein the design and then off the slash surface entirely: the engine refuses
a mod command namedlore, which the plugin's ownloreskill owns, and registering one skips
the wholesession.starthook — so the pane ships no slash command of its own, and its only
entry point is the module'smcp__opum-lore__dashboardtool, which theloreskill routes to.
/lore dashboard(and the plain words "lore dashboard") opens the pane as it stands;
dashboard full,dashboard <doc-id>anddashboard search <text>map to the tool'sfull,
docandqueryinputs, and every argument that does not start withdashboardgoes 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, andengines.bunnarrows 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 the1.4.2pin (10/20 and 17/20 CI runs) and never on1.3.14(0/20 in both
windows), and that race is what failed the required ubuntulint · typecheck · testleg even on
diffs that cannot reach a test. The1.4.2floor existed for the LCLI-648 parser panic, which
DEC-163 (8) works around by avoiding the construct — lore's source carries noBun.Transpiler
and no top-leveldeclarebinding, so the panic cannot reach shipped code. The floor test that
exercises the repro now skips itself on1.3.14and names LCLI-648, re-arming if the pin moves
forward again. Breaking for consumers who readengines.bun, as LCLI-648's move was. -
The
lore agent contextpack footer now counts the eligible deck, and a
zero-score omission carries its own reason (LCLI-680; ODOC-437 slice 1, AC1).
total,shownandtruncatedare 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 reportstruncated: falsehowever many zero-score candidates it excluded (measured on this
repository's ownimplementationprofile: the LCLI-289 pack now reads
198 of 198; truncated: nowhere 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 reasonomitted-by-relevance,
distinct fromomitted-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'stotal/truncatedchanges
as described, so that envelope'sschemaVersionis bumped2→3under
cli-contract §7.1 — a meaning change to existing fields, scoped to thatkind.
Theagent.workflow.projectionenvelope is bumped1→2by the same change,
since it embeds a pack compiled by the same selection code, sototal,shown,
selectedCount,topScoreandreasonmove inside it too (lore help --json
now reportskindSchemaVersions: {"agent.context.export": 3, "agent.workflow.projection": 2}); its embedded pack stays hit-free. A source
dropped whole by relevance now reads a differentreasonthan one dropped by
budget; the newreasonvalue 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'sagent-profile-capacitymeasurement previously excluded the bundle-wide query
section a reallore agent contextpack 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-budgeton 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 forrows - 6inline, where the engine caps
an inline pane atrows - 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.dockColumnsthen beat anyway — and thedashboardtool answered with the size it
asked for rather than the size that drew. The module now asksrows - 11inline 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...
Lore CLI 0.12.0
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 isorigin/devplus every open pull request intodev, discovered
throughgh; given one or more ref names, it is exactly those refs, resolved locally with no
forge and no fetch. Every hit gainsrefProvenance{ref, pullRequest, sha}— a separate key
from--workspace'sprovenance, which carries an unrelated workspace identity — and every
answer reportscoverage{complete, population, discoveredAt, refsRead[], refsUnreadable[]}
as an envelope key betweendataandprincipal, 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/devalways 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-lessgit fetch(objects only) andgit archiveinto a temporary
directory, andlore syncrefuses the flag, since a branch's managed blocks regenerate only
from that branch's own records. An incomplete read is adrifterror at exit6naming the
unreadable refs and carrying the coverage object in the error'sinput, with nothing on
stdout;--allow-partialanswers at exit0withcomplete: falseinstead. With noghon
PATH, or anoriginthat is not GitHub, the run degrades topopulation: "dev-only"the same
way — incomplete coverage, never an uncaught failure.
Changed (breaking)
-
The pinned Bun moved from
1.3.14to1.4.2(LCLI-648, pair with quest-cli QCLI-411).
Marked breaking becauseengines.bunmoves 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.14mis-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
on1.3.14and exits 0 on1.4.2, andtest/bun-declare-binding.test.tspins that on the
pinned runtime. Two upstream behaviour changes ride along.Bun.Globnow descends
into dot-directories by default —.github/workflows/*returns 0 matches on1.3.14and 4 on
1.4.2(dot: truereturned 4 on both) — which changes what a dottedlore replace --in
pattern matches, previously nothing. AndBun.TOML.parserejects an imprecise bare integer
literal that1.3.14silently rounded; both runtimes still surface a stablevalidationerror
naming the config file, andtest/config.test.tscovers each shape. -
lorenow refuses to drive aquestthat is not its exact pair version (LCLI-650; DEC-31
adopting the opum-doc ADRlock-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 — exit6,
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 initdetects 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. Aquestselection with noquestonPATH
stops with the install pinned to lore's own exact version (npm install -g @opum-ai/quest@<lore's version>) plusquest init(dropped when the repository already has a
Quest workspace) and the rerun; abacklogselection likewise namesbacklog.mdand 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 questor--tracker backlog
with the CLI missing or the project uninitialized used to warn and persist a selection (exit0)
and now stop with the instructions (exit3/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-trackerand--no-install-trackerare 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-migrationbacklog/removal offer is gone with the wizard's migration arm
(the flag path's--remove-backlog/--no-remove-backlogis unchanged),--no-trackerremains the
documented opt-out, and a bare non-interactivelore initstill pins the default backend and
probes nothing (LORE-260). The remedy names lore's own exact quest version, neverlatest, 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
crashinglore 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 exited1
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 avalidationrefusal (exit6) with a remedy, never an uncaught crash. Where a
duplicate heading takes a slug (a quoted# Overviewbeside 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#overviewwhere a quoted# Overviewtook the slug resolves to the QUOTED heading,
not the top-level one the pre-fix renderer picked; anchor#overview-1for the top-level heading.
Classified### Changedrather 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-latestrun now refuses when any package's currentlatestis 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 movedlatestahead would move it backwards, the move the ADR refuses.planPromotionnow
makes the same numeric comparison on the resume path, before any write, naming the package and
both versions; a package already at--versionstays accepted, which is the partial state a
resume exists for. The comparison is by the release a live value leads with, so a registry
latestof5.7.0-rc.1counts as newer than5.6.7and refuses, while5.6.7-rc.1or
5.6.7+build.7is not newer than5.6.7and still resumes. On a fresh run, a package whose
currentlatestis not a plainX.Y.Znow 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 guardmain()—launcher-equivalence,pair-receipt,
promote-latest,version-parity,github-releaseandcheck-breaking-bump— and all six
comparedresolve(process.argv[1])withfileURLToPath(import.meta.url). That is false through
any symlinked path, becauseresolve()never follows a link while Node resolvesimport.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-basedisMain()inscripts/is-main.mjs, andtest/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 --helpexits 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.mjsis 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...
Lore CLI 0.11.0
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 checkexits6withschema-driftfindings until you runlore schema exportand
commit the regenerated.lore/schemas/*.json. That covers the re-stamped existing schemas plus
the newconstitution.schema.jsonandconstants.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 agentsmanaged 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 faillore agents --checkunder an older lore, and an older
lore would strip the new lines again. Upgrade every CI job that runslore agents --checkin
the same change. A repository with neither document is unaffected: its block is byte-identical.
Added
-
Built-in
Constitutiondocument type (LCLI-595, OPAG-425 R1-R4, R9). At most one per bundle.
It carries requiredversion,ratified,last_amendedandamendment_authority, and the
sections Principles, Governance and Amendment log.### P<n>. <Name>principles need an RFC
2119 keyword,Rationale:andCheck:.lore validateandlore checkboth enforce the
shape, andlore new constitutionwrites a document that passes. -
Built-in
Constantsdocument 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-portis#servicehttp-port).lore check:- compares every entry whose
source_of_truthnames a git-tracked JSON, TOML or YAML file and
key against that file (new rulesource-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 (
readCountsin--json).
No finding ever prints what a source file holds.
lore new constantswrites a document that
passes. - compares every entry whose
-
lore agentsrenders 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 = valuefor active entries flaggedhot.lore agents --checkreports drift when either
document changes. Document text is rendered inert. -
lore agent contextpins 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 thatlore agent projectandlore agent context --contractembed.
It carries the catalog reasonconstitution, 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
Constitutiontype is never auto-pinned. --workspacepacks are unchanged.- The auto-pin counts toward the budget like any pin, so a Constitution the budget cannot hold
exits6. 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
reasonvalue, andpackDigest/contextDigest
change for any bundle that has a Constitution.
- A profile that already references the Constitution keeps its own reference and gets no second
Changed
- BEHAVIOUR CHANGE:
lore checknow fails on the error-tierfrontmatterandrequired-section
findingslore validatereports, for every type (LCLI-606). Ships in a lore minor release.
Until nowlore checkcould exit0over a document thatlore validatefailed. It now exits
6on every such finding: a missing required section (an ADR without## Consequences, a Story
without## Acceptance criteria), a missingtype, a missing or mistyped field (including one
your own.lore/profile.tomlrequires), and an invalid enum value (for example an OKF 0.2
lifecyclestatusthat is notdraft,stableordeprecated). The findings keepvalidate's
rule names and messages, andcheckjudges each file exactly asvalidatedoes, with its
repository-relative path and thedocs/root's OKF version and profile, even in a scoped
lore check <dir>. A stray second frontmatter fence stays one finding, under the
double-frontmatterrulecheckhas used since 0.4.0. Before upgrading, run
lore validate: itsrequired-sectionfindings and error-tierfrontmatterfindings are
exactly whatlore checkwill now fail on. Files without frontmatter are still skipped.
validate's error-tierquote-safetyfindings, and its resource and warning-tier findings, stay
validate-only. Atasks:-linked document with invalid frontmatter now draws an ordinary
frontmatterfinding and is left out of reconciliation. Before, it aborted the run with the
first such error only (a thrown error on stderr,complete: falsein--json). The exit code is
still6. The--jsonreport's shape is unchanged: the new findings are new values of the
existingrulefield. 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
Constantstype addsownerandlast_reviewedto the profile-wide
frontmatter key order (LCLI-596). A document of any type that already carriesowner:has it
reordered on its next lore rewrite. Measured 2026-09-26: 0 fleet documents affected.
Fixed
lore unlinkno 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 linknow guards its whole-list--docwrite with--if-revisiontoo. 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 onlore unlinkor 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 (
managedscope) 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 --forcenever runs an update against it and
never prints--scope managed. Installed or disabled, it reportsupdate: not-runwith 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 linkno longer half-applies when Quest has no actor declared (LCLI-582). With
LORE_QUEST_ACTORunset, it used to write the concept'stasks:frontmatter, then fail the
back-reference edit with exit6, leaving a one-sided link. It now refuses before any write, so
the exit6leaves 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-refskips the check.
Lore CLI 0.9.3
Added
- Every plain
lore agent contextpack 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 hitssection lists up to
threelore queryhits for the task that the pack does not already quote, as id, title and
snippet, with no bodies. In--jsonthese are three additive fields onagent.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), andqueryHitsSectionOmitted(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-tokensthat 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,packDigestandinputRevisionsare byte-identical to 0.9.2's, so a
document outside the profile's catalog cannot move a pinned digest (Amendment 1). lore help --jsonlistskindSchemaVersions, the per-kindschemaVersionoverrides
(additive; cli-contract §7.1). Today it is{"agent.context.export": 2}.
Changed
lore agent context <unknown profile>exits0, not3. It degrades to the query section
plus a warning, in the pack and on stderr, and setsprofileMissing: 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 projectandagent context --contractare unchanged on an unknown profile.- BREAKING (
--json): theagent.context.exportenvelope'sschemaVersionis2(was1),
for the exit3→0remap above — settled by the ADR's Amendment 1 (opum-docmaina8bb596)
and recorded in cli-contract §5.6. The bump is scoped to that onekind: every other envelope,
agent.workflow.projectionincluded, staysschemaVersion1. A consumer pinned to1for
lore agent context --jsonshould readprofileMissingwhere it relied on exit3, then
accept2.
Fixed
- The README quickstart runs (LCLI-571). It named a
lore new spec --storyoption that never
existed, and it coupled Backlog.md task ids that no fresh repository has, whilelore 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
Changed
- Agent guidance now starts with retrieval:
lore querythenlore read, not browsing
docs/index.md(LCLI-573, OPAG-378). A newlore instructions retrievaltopic teaches
single-repository search. The overview loop and every generated bridge (the Claude and Codex
skills and theCLAUDE.md/AGENTS.mdnudges) 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 listsread,typesand
backlog. It also states--max-tokensas the hard ceiling LCLI-478 made it: the old text
called it advisory. Regenerate it withbun run scripts/plugin-skill.ts --write. This file
reachesopum-loreplugin users at the next tag. - The generated skills drop the Backlog/
.codex"commit-side-effect preflight". It routed
commands through a retiredbacklog-handovergate. What remains is accurate:lore link,
unlink,renameandsynccommit tracker files only on the Backlog backend. Thesyncand
initsummaries inlore helpno 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 --checkexits 6. TheCLAUDE.mdblock
reportsupdated, andlore agentsrewrites it. The repo-mode.claude/skills/lore/SKILL.md
reportsprotected, because its bytes differ from what this release generates, so only
lore agents --forcerewrites it. Repositories onskill_source = "plugin"have no such file.
Lore CLI 0.9.1
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 storyscaffolds intodocs/stories/again, and still writestype: 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 runslore new storyand then
addressesstories/<slug>, and it broke a consumer that asserts the folder. Until 1.0.0 the
output directory follows the spelling you typed: theStoryspelling, in any case, scaffolds into
docs/stories/, andlore new arckeepsdocs/arcs/. The writtentype:is always the
canonicalArc, so no new document carries the deprecated spelling. Documents 0.9.0 already wrote
underdocs/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 namedStoryalso scaffolds intodocs/stories/again, as it did before 0.9.0.
Deprecated
- What 1.0.0 removes with the
Storyalias: theStoryinput spelling (lore new story,
type: Storydocuments,lore query --type Story),story.schema.json, and thedocs/stories/
output path thatlore new storyuses. From 1.0.0,lore new arcis the only spelling and
docs/arcs/is the only scaffold directory. Documents already underdocs/stories/are not
moved by lore; move them withlore renamebefore upgrading if you want them indocs/arcs/.
Lore CLI 0.9.0
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_typeindeterminateis a newlore checkoutcome, and it is a breaking
CLI-contract change. A consumer that freezes the exit-code taxonomy (023456),
or that branches only on6, will misread it. Exit7means "cannot judge this from here":
do not auto-repair it, and do not runlore schema exportorlore syncas a fix. Read
git logon the named file. A run with both6-class and7-class findings exits7
(OPAG-373). The capability manifest's error taxonomy gainsindeterminate: 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 reportedstale, and onelore schema exportre-stamps all
of them. Only an unstamped schema that is also an orphan (no type owns it) reports exit7.
The Story -> Arc rename below addsarc.schema.json, which a pre-0.9.0 bundle lacks and which
reportsmissing(exit6). The same export writes it. - Fleet consumers skip 0.8.0. Move the lore pin to
0.9.0AND runlore schema exportin 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.jsonwith 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 exportwill no longer
prune it. It is kept and reported instead. A legitimate removal now costs one deliberaterm.
That is the design: a leftover file needing a deliberatermis 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 besideprofileDigestinsrc/core/schema.ts. lore schema export --jsongainskeptUnattributable. It lists the orphans that were kept
because their stamp is absent or foreign.removednow 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 manualscripts/publish-release.shpath, 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 initthrough the same emitter, writesx-lore-generator.profileDigestinto every emitted
schema, alias files included. The value issha256over a documented, versioned projection of
the compiled profile's type definitions. Editors and validators treat the key as an inert unknown
keyword. lore checkexit7, ruleschema-unattributable(LCLI-565). An orphaned schema with a
matching stamp is stillorphaned(exit6, prune advised). An orphan with a differing or absent
stamp isunattributable(exit7), 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 anderror_typeare kept.- Deprecated type aliases in profiles (LCLI-553). A
[[types]]table may declarealiases. An
alias resolves to its canonical type everywhere a type name or slug is read, andlore schema exportemits a byte-identical schema file for each alias spelling. Name and slug collisions are
rejected.
Changed
- The built-in
Storytype is nowArc, andStorystays as a deprecated alias until 1.0.0
(LCLI-554, OPAG-255). Existingtype: Storydocuments keep working.lore new Storywrites
type: Arc, and both spellings scaffold intodocs/arcs/.lore query --type Storymatches
documents of either spelling, and required-section enforcement applies to aliased documents.
Consumers gainarc.schema.jsonbeside a byte-identicalstory.schema.json.
Fixed
lore schema exportno 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 committedADR.schema.jsonand theadr.schema.jsonthat 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 onlyadrschema. 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 checkhad 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: atype: Storydocument resolved toArcand was then rejected by
the schema's single-valuetypeliteral, solore linkstill refused it.typenow accepts the
canonical name and every alias. An aliasless type keeps itsconstform 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
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 — settinguse_immutable_subject: falseis accepted and has no
effect. 0.8.0 therefore goes out through the manualscripts/publish-release.shpath, 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 openingprofile.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 checknow detects committed-schema drift (LCLI-539). A.lore/schemas/*.jsonthat no
longer matches what the profile would generate is reported rather than silently trusted.- This can turn a previously-green
lore checkred 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 runlore checkas 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, andlore schema exportcleared it.
- This can turn a previously-green
Fixed
lore new <multi-word-type>is reachable from its own slug (LCLI-534).Attested Computationis the one multi-word built-in and it was unreachable fromattested-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-computationverbatim, emitted no$schemamodeline, scaffolded noruntime
field, andlore validatedegraded 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 tolore new.lore newscaffolds a profile type's declared sections (LCLI-535). A type'ssectionsare
enforced bylore validatebut were never written bylore 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, andlore validatewill say so.lore new --template <name>.mdresolves the file you named (LCLI-536). The extension was
appended to a name that already had one, so lore looked forfeature.md.mdand 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 --helpadvertises a version the exporter accepts (LCLI-512). Help, the manifest
andcli-surface.mdall claimed--schema-version 1.0and shipped it as a worked example while
the exporter had moved to1.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 unlinkno 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.
- Support is detected by presence, never by a version comparison. Passing the flag
- Retained snapshots now carry the ADR-0021 relation qualifiers (LCLI-540).
edgeValuedropped
statement,versionandrelationOrdinal— the three fieldsProjectionEdgeRecorddeclares
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 thatlore changed
could never report a relation re-pin, andlore provenancecould not recover which
claim_versionwas 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
stayslore-retained-snapshot/1: every snapshot written before this release still validates.
lore-retained-snapshot/2was considered and deliberately NOT taken, so that existing snapshots
keep validating; the qualifiers are additive and optional precisely to make that possible. lore snapshot retainno 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.shstays 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 anexithandler, 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...
Lore CLI 0.7.0
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 classicrepo: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: falseis accepted and has no effect. 0.7.0 therefore goes out through the
manualscripts/publish-release.shpath, 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, sogit 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, solore read <id> | tail -n +3recovers the body
byte-for-byte.- A separate operation from
lore contextrather than a flag on it.contextassembles 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.
- A separate operation from
Changed
-
lore context --max-tokensis now a hard ceiling, not an advisory label (LCLI-478). The
emitted pack'stokenEstimatenever exceeds a supplied budget. Previously an oversized target was
emitted in full and merely flaggedtruncated— the caller asked for a guarantee and received a
suggestion, with no way to tell which they had got.- To stay within the budget,
contextdrops neighbors nearest-first and then, only if the target
still does not fit, the target's ownbody. 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.omittedcarries{ 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-tokensthe 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
6naming the
required figure, matchinglore agent context's existing refusal for the same situation, rather
than answered with something unusable. target.bodyis now optional incontext.export, and the plain renderer prints an explicit
notice in its place pointing atlore 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
schemaVersionbump? 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 omittarget.body, which
0.6.2always emitted — an oversized target went out in full, merely flaggedtruncated. It is
scoped as non-breaking for two reasons: the field is absent only when the caller supplies
--max-tokensand so opts into a bound, never on an unbudgeted call; anddata.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 pinningschemaVersion: 1that reads
target.bodyunconditionally on a budgeted call must readomitted.fieldsinstead.
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-tokensis a
guardrail, not a guarantee" now says what is actually approximate — thechars/4unit, not the
enforcement — and records that the previous wording described the defect. The agent-profile spec
no longer points atlore context --depth 0as 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.
- To stay within the budget,
-
lore graph,query,context,pathandimpactnow name the retrieval backend that served
the request (LCLI-499). Their--jsondatacarriesbackend:"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 readingretrieval.ts,workspace-retrieval.tsand 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/contextandcore/traversal
stay storage-neutral: which backend answered is a fact about the load, not about the result.
The--jsonenvelope is versioned additively (cli-contract §7), so noschemaVersionmoves, 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 aboutbackend.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.
- Present on every successful response, never only on a degraded one. A marker that appeared
-
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 aslinkalongside every "see also" aside. An
argument recorded that way is legible to a reader and invisible tolore graph,lore pathand
lore impact, which are the three commands anyone would use to ask what a change breaks.relationsis a new reserved frontmatter list. Each entry carries akindand atarget,
plus optionalstatementandversionqualifiers that make the reference precise: which
statement, at which version.kindis one ofrequires,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_versionare a third axis beside the two
ADR-0019 separated. Lore never derives them fromstatus, fromlore_task_status, or from each
other, and never writes them itself.supportedis deliberately notprovedandcheckedis
deliberatel...