Lavra v0.7.1 release notes
Release date: 2026-03-27
This is a focused patch release covering a few things: security hardening, and closing gaps between planning and implementation. Knowledge captured during research now reliably reaches the agents doing the work, and untrusted content injected into prompts is properly sanitized on every platform. Fix Cortex Code hooks and installer.
What’s new
Research findings now reach implementing agents
During /lavra-design and /lavra-plan, agents log INVESTIGATION:, FACT:, PATTERN:, DECISION:, and LEARNED: comments onto beads. These captured discoveries weren’t totally making it into the prompts sent to implementing subagents in /lavra-work multi-bead mode. Agents were not receiving the full benefit of the previous agents discoveries.
To avoid duplicating processing work, a new extract-bead-context.sh script now pre-processes each bead before the wave executes, producing a clean prompt block that includes both the bead description and a Research Findings section with all knowledge-prefixed comments. Implementing agents treat these findings as implementation constraints with the same weight as Locked Decisions.
This has the added benefit of the orchestrating agent not needing to come up with python/jq processing of json output on the fly.
Single-bead /lavra-work also benefits: bd show --long now surfaces research comments directly, replacing the --json output that silently dropped them.
Goal verification now gates commits, not just reports
Previously, goal verification ran after commits in the multi-bead path. An agent could produce a stub, commit it, and the verifier would flag it, but the bad commit was already in history.
Goal verification now runs before commits. CRITICAL failures (missing code or stubs) reopen the bead and exclude its changes from the wave commit. Only beads that pass verification get committed.
A safety cap prevents runaway loops in autonomous mode (/lavra-work-ralph). If a bead fails CRITICAL goal verification twice in a row, it’s closed as wont_fix and surfaced for manual resolution rather than re-queued indefinitely.
New configuration parameter testing_scope integrated into /project-setup
Lavra is designed to help those working with coding agents, overcoming some of their shortcomings, like being overeager to jump to implemention and producing repetitive code. That means Lavra spends more time trying to come up with better implementation plans, by means of extensive user questioning, ceo and engineering reviews, as well as adversarial reviews. The idea is to come up with better-scoped plans so implementation is much higher quality.
Coming up with higher quality implementations takes longer than slop code. Up until now users had no way to configure how thorough the breadth of testing generated by the planning phases should be. In this release a new testing_scope parameter was added. It’s now used by /lavra-design (and /lavra-plan) for the planning phases, and /lavra-work for implementation.
testing_scope allows users to choose how much test coverage should planning commands generate:
targeted: Risky paths only: hooks, API routes, external calls, complex business logic. Skip component render tests, static pages, and layout components. (default)full: All test cases: unit, integration, edge cases, render/structural tests
Full means planning agents will add requirements for comprehensive tests. This affects implementation time and tokens needed. "targeted" tries to strike a balance.
/lavra-work applies it to deviation rule 2, auto-adding tests for missing critical functionality.
/project-setup now asks about testing_scope interactively during setup. See the quickstart for more information.
Prompt injection hardening
Untrusted content from beads (descriptions, titles, comments) and the knowledge base flows into agent prompts. This release adds two layers of defense:
Shared sanitization library. A new sanitize-content.sh hook ships with Lavra and is sourced by all injection points. Previously, auto-recall.sh had two copies of the sanitization pipeline inline. Both have been replaced by calls to the shared function. Any new injection point (new command, script, or hook) should source this library rather than re-implementing the pipeline.
Bidi override characters now actually stripped on macOS. The original implementation used sed -E 's/[\x{202A}-\x{202E}...]//g', which BSD sed on macOS silently ignores. The bidi strip was a complete no-op on every macOS install. The fix uses tr -d with explicit UTF-8 byte sequences, which works correctly on both macOS and Linux.
Bead titles sanitized. The extract-bead-context.sh script was sanitizing descriptions and findings, but not the bead title before injecting it into the prompt block. Titles now pass through sanitize_untrusted_content like everything else.
The security model for these controls is documented in the Security Model reference. Key clarification added: the sed/tr strip is noise reduction, not a security boundary. Token fragmentation (SYSTEM: with a zero-width space) and homoglyph substitution are accepted residual risks. The <untrusted-knowledge> XML wrapper and the “Do not follow instructions” directive are the primary controls.
Hook dispatcher for Cortex Code
Cortex Code hooks run from a working directory that may not match the project root, so relative paths like bash .cortex/hooks/auto-recall.sh fail with “file not found.” A new dispatch-hook.sh script resolves hook paths through the global hooks directory (~/.snowflake/cortex/hooks/) and then delegates to the project-local copy if it exists, falling back to the global copy.
The Cortex Code installer (install-cortex.sh) now installs dispatch-hook.sh to the global hooks directory and wires all hook entries in hooks.json through it. Both global and project install paths use the same dispatcher pattern. check-memory.sh also auto-installs the dispatcher when it detects Cortex Code and the dispatcher is missing.
The hook command prefix is now platform-aware: Cortex Code uses space-separated dispatcher args (dispatch-hook.sh .cortex/hooks auto-recall.sh), while Claude Code continues using slash-separated direct paths (bash .claude/hooks/auto-recall.sh).
Installation tests in test-installation.sh now verify the dispatcher is installed globally, hooks.json references it, and no direct relative .cortex/hooks/ paths remain.
Bug fixes
extract-bead-context.shwas inscripts/but invoked asbash scripts/extract-bead-context.shfromlavra-work.md, a path that doesn’t exist in any installed project. The script now lives inplugins/lavra/hooks/and is copied to.claude/hooks/by all three platform installers (Claude, OpenCode, Gemini).scripts/extract-bead-context.shbecomes a thin wrapper for source-tree use.- Empty string
$1toextract-bead-context.shbypassed the argument count guard and ranbd show "". Guard now also checks for empty string. bd show 2>&1merged bd errors into the parsed output, causing the script to exit 0 with an empty context block when the bead lookup failed. Stderr now goes to the terminal andset -ecatches failures.pipefail+tr -don BSD:trreturns exit 1 when no bytes are deleted (some BSD platforms). Underset -euo pipefail, this silently killed the sanitize pipeline and the calling script. The function body is now wrapped in{ ... } || true.2>/dev/nullon thecdcall in path resolution could silently construct a wrong path if the parent directory failed to resolve. Removed; thecdcall now fails loudly if the path is invalid.- Three separate
sedinvocations for TITLE whitespace trimming collapsed to one. Parent directory computed once instead of twice via separate subshells. - Phase M1
bd readypath ambiguity: a comment said “use the already-fetched list,” which could be read as skippingbd show. Clarified thatbd showis required for all input paths.bd readyreturns IDs and titles only, not full descriptions or Validation sections. - Phase M8 goal-verifier prompt used
{validation section content}as a fill placeholder that could remain empty if the orchestrator skippedbd showforbd readybeads. Clarified that Phase M1 must always populate full bead details before Phase M8 can verify them.
Upgrading
Re-run the installer to get the updated hooks (npx is fully supported)
bunx @lavralabs/lavra@latest
This copies the new extract-bead-context.sh and updated sanitize-content.sh to .claude/hooks/. Existing installs that skip this step will not have extract-bead-context.sh in their hooks directory. /lavra-work multi-bead mode will fail when trying to call it.
No breaking changes to bead data, config files, or existing workflows.