Upgrading to edikt v0.9.0
v0.9.0 removes write-time governance. edikt no longer injects rule text into a Write or Edit while it is happening. Rules reach the model before work starts, through the always-loaded core and the topic files, and the phase-end review checks the result.
If you are on v0.8.x, the upgrade takes a few commands and one recompile. If you are on an older line, upgrade to v0.8.0 first: see Upgrading to edikt v0.8.0.
If you're on v0.8.x
Commit your governance files first, so you can see what the upgrade changed.
If you installed with Homebrew, update the launcher first. edikt upgrade fetches the payload and never replaces the binary:
brew upgrade edikt # Homebrew installs onlyThen:
edikt upgrade # fetch the v0.9.0 payload
edikt upgrade-pin # move this project's edikt_version to v0.9.0Then, from inside Claude Code in your project:
/edikt:upgrade
/edikt:gov:compile
/edikt:doctorWhat each step does:
/edikt:upgraderemoves the two retired hooks from.claude/settings.json(it printsremoved verify-gate.shandremoved inject-directives-pre.sh), deletes the retired.claude/rules/governance/directive-index.yaml, removes plan files written by an older schema, and installs the updated agents./edikt:gov:compilere-renders your rules. Every directive that used to be injected at write time now lives in its topic file, so a project that compiled on v0.8.x needs one recompile to pick that up./edikt:upgradedoes not run it for you./edikt:doctorchecks the result. Read the next section before you treat a new red line as a regression.
There is no sidecar schema change. You do not need to re-extract your corpus.
What changes for you
Rules are no longer injected at write time
PreToolUse now does one thing: it guards edikt's managed regions (INV-005). It no longer injects directives or blocks a write on a directive. Every directive renders in its topic file, or in its skill package when the topic has no scoped rules file. An empty Directives region in a topic file means that topic has no directives.
Between upgrading the binary and running /edikt:upgrade, your settings still register the two retired hooks. Claude Code reports a missing hook command and carries on, so nothing is blocked. edikt doctor reports registered hook retired in this version — run /edikt:upgrade.
edikt doctor can go red on a project that was green
An accepted ADR, invariant or guideline with no *.edikt.yaml sidecar next to it is now an error, not a warning. doctor names the command to run for each kind: /edikt:adr:compile, /edikt:invariant:compile or /edikt:guideline:compile. A proposed artifact is not counted.
doctor also counts a behavioral verify that has no human_approved_at as a warning and names it. Approve it with /edikt:sidecar:approve. If your CI asserts on doctor's warning count, expect it to move.
gov compile no longer fails on a directive's verify:
The verify still runs and prints its report. Its result no longer changes the exit code, which now says only whether the render worked. If CI relied on gov compile to catch a failing directive verify, gate on edikt verify instead.
Scripts that call edikt need to say who they are
A command that changes files now refuses with exit 4 when it is not run from a terminal and EDIKT_INVOKER is not set. A terminal always works. In CI and scripts, set:
export EDIKT_INVOKER=ciThis is for steering, not security. The value is self-declared.
edikt verify all deletes old reports
It keeps the newest report for each id under .edikt/state/verify/ and deletes the rest. That directory is a cache, not an archive. Plan-phase reports are never deleted.
phasea verify has a new exit code
Exit 6 means an item stopped because each retry made it worse, with retries still left. Exit 5 still means the retry budget ran out. If you only check for zero or non-zero, nothing changes for you.
Removed config keys
features.evidence-gate, hooks.injection.bounce_budget and hooks.injection.dedup_scope no longer do anything. You can delete them from .edikt/config.yaml.
Migration has one home
If an artifact still carries an in-body directive block, or its sidecar is still schema_version: 1, run /edikt:migrate. /edikt:upgrade, /edikt:gov:compile, /edikt:doctor and /edikt:init point you there instead of migrating on their own.
Fixes you may notice
- The phase-end evaluator and post-flight now work when Claude Code is signed in with OAuth. Before, every automatic phase-end check came back BLOCKED under an OAuth login.
- The
Active plan:line names the plan again for plans that start with frontmatter. /edikt:adr:newcan now accept the ADR it creates. Before, its acceptance step could never pass.gov compile --checkno longer rewrites sidecars.- The sidecar extractor's turn budget is 20 (was 8), so long ADRs no longer fail silently.
The full list is in the v0.9.0 release notes.
Known issues
gov reextract refuses to run on v0.9.0, because the extraction contract this release ships has not passed validation. Compiling a sidecar for a new or edited artifact and gov compile both work as normal. Only re-extracting an existing corpus through a changed contract is blocked. Do not work around it with --skip-fixture-proof. That flag is for the validation run itself.
The Known issues section of the v0.9.0 release notes lists every test suite that fails on this release and why.
Related
- Keeping edikt Up to Date: the general upgrade flow and version history
- Upgrading to edikt v0.8.0: the step before this one
- Sidecar Migration: moving in-body blocks into sidecars