Migration guide

Version upgrades and breaking changes

On this page

Overview

This page documents breaking changes between versions and how to upgrade. klaudiush follows semantic versioning - breaking changes only happen in minor version bumps during the pre-1.0 phase.

v1.24.0 - XDG base directory migration

v1.24.0 moves all global/user-level paths to follow the XDG Base Directory specification. Files that previously lived under ~/.klaudiush/ are split across config, data, and state directories.

Old pathNew path (XDG)
~/.klaudiush/config.toml$XDG_CONFIG_HOME/klaudiush/config.toml
~/.claude/hooks/dispatcher.log$XDG_STATE_HOME/klaudiush/dispatcher.log
~/.klaudiush/exceptions/state.json$XDG_DATA_HOME/klaudiush/exceptions/state.json
~/.klaudiush/exception_audit.jsonl$XDG_STATE_HOME/klaudiush/exception_audit.jsonl
~/.klaudiush/crash_dumps/$XDG_DATA_HOME/klaudiush/crash_dumps/
~/.klaudiush/patterns/$XDG_DATA_HOME/klaudiush/patterns/
~/.klaudiush/.backups/$XDG_DATA_HOME/klaudiush/backups/
~/.klaudiush/plugins/$XDG_DATA_HOME/klaudiush/plugins/
# Default XDG locations (when env vars are not set)
# $XDG_CONFIG_HOME = ~/.config
# $XDG_DATA_HOME   = ~/.local/share
# $XDG_STATE_HOME  = ~/.local/state

# So the global config defaults to:
~/.config/klaudiush/config.toml

# Logs default to:
~/.local/state/klaudiush/dispatcher.log

What happens on upgrade

On first run after upgrade, klaudiush detects the old ~/.klaudiush/ directory and moves files to their XDG locations. The migration is automatic and idempotent - running it twice is safe.

  • Files are moved, not copied
  • Symlinks are created at ~/.klaudiush/config.toml and ~/.claude/hooks/dispatcher.log for backward compatibility
  • Files that already exist at the destination are skipped
  • Custom absolute paths in your config are not affected
  • Project-local paths (.klaudiush/config.toml, .klaudiush/patterns.json, .klaudiush/plugins/) are unchanged

Verifying the migration

Run the XDG doctor category to check migration status and directory permissions:

# Check XDG migration status and directory layout
klaudiush doctor --category xdg

# Auto-fix: migrate remaining files and create missing directories
klaudiush doctor --fix --category xdg

New environment variable

KLAUDIUSH_LOG_FILE overrides the log file location. When set, klaudiush writes logs to this path instead of the XDG state directory.

v1.18.0 - JSON stdout output

v1.18.0 changed how klaudiush communicates with Claude Code. Instead of exit codes, it uses JSON stdout for all responses.

Before (v1.17 and earlier):
  Block: exit code 2, formatted text to stderr
  Allow: exit code 0

After (v1.18+):
  Block: exit 0, JSON stdout with permissionDecision: "deny"
  Allow: exit 0, JSON stdout with permissionDecision: "allow"
  Crash: exit 3 (panic recovery)

Exit code change

If you have scripts that check for exit code 2, they need to parse JSON stdout instead. Exit code 2 is no longer used.

The reason for this change: Claude Code conflates exit code 2 with user denials. With JSON output, the model gets structured error information and can self-correct. See ADR-0001 for the full rationale.

JSON output format

The JSON output includes separate fields for model-facing and user-facing messages:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "[GIT001] Message for the model",
    "additionalContext": "Extra context"
  },
  "systemMessage": "Message for the user"
}
FieldPurpose
permissionDecisiondeny or allow - replaces exit code
permissionDecisionReasonError code and message for the model to self-correct
additionalContextExtra context the model can use
systemMessageMessage shown to the user in the terminal

Upgrade steps

For most users, upgrading is just updating the binary. Configuration files are backwards-compatible - all existing configs continue to work.

# 1. Update klaudiush
brew upgrade klaudiush
# or
curl -sSfL https://klaudiu.sh/install.sh | sh

# 2. Verify version
klaudiush version

# 3. Run doctor to check setup
klaudiush doctor

# 4. Test validation still works
echo '{"tool_name":"Bash","command":"git commit -m fix"}' | klaudiush --hook-type PreToolUse

klaudiush also has a self-update command:

# Check for updates
klaudiush update --check

# Update to latest
klaudiush update

# Update to specific version
klaudiush update --to v1.20.0

On first run after upgrade, klaudiush automatically backs up your existing config before applying any changes. You can restore the backup with klaudiush backup restore if anything goes wrong.

© 2026 Smykla Skalski Labs