Changelog¶
All notable changes to haven are documented here.
Format: Keep a Changelog. Versioning: Semantic Versioning.
[v0.9.0] — 2026-03-27¶
Added¶
-
haven telemetrysubcommand — telemetry management is now a proper subcommand (haven telemetry status,haven telemetry on/off). Top-level shortcutshaven note,haven bug, andhaven questionare also added for quick feedback capture. -
haven status --verbose— shows internal state detail (lock files, paths, raw state) useful for debugging. -
--filterand--countflags onhaven list— filter listed files by pattern and/or print only a count. -
haven update <file>— top-level alias forhaven add --update. -
--cmd-nameflag onhaven completions— allows generating completions for an alias (e.g.h) instead of the default binary name.
Fixed¶
-
haven ai removeaccepts source URL —haven ai removenow matches by source URL (or suffix) in addition to skill name, and shows available skill names when no match is found. -
Local platforms registry path —
havennow reads the local platforms registry from~/.haveninstead of the old~/.dfilespath. -
Atomic writes for state files —
state.jsonandhaven.lockare now written via temp+rename to prevent partial writes on crash. -
apply.lockrace condition — lock file creation now usesO_EXCL(create-new) to eliminate a TOCTOU race. -
Process liveness check — replaced the
kill(0)subprocess approach with thenixcrate for cleaner cross-platform signal handling. -
Dry-run output memory leak — removed
.leak()call in dry-run output path. -
Stale
dfilesreferences — remaining internal comments and test names referencingdfileshave been updated tohaven.
[v0.8.0] — 2026-03-27¶
Added¶
-
CLAUDE.md staleness detection —
haven statusnow shows a~marker in the[ai]section when the haven-managed section in~/.claude/CLAUDE.mdis out of date. This fires when a skill snippet file (all.md/claude-code.md) has been edited since the lasthaven apply, or when a new skill has been added but not yet deployed. Runhaven apply --aito bring CLAUDE.md up to date. -
Snippets at the top of the managed section — skill snippets from
ai/skills/<name>/all.mdandai/skills/<name>/claude-code.mdnow appear before the skills/commands listing inside the haven-managed block. Claude Code reads snippets earlier in the file, ensuring they take effect before the index.
Fixed¶
-
False drift on
CLAUDE.md—haven statusandhaven diffno longer reportMorMCdrift on~/.claude/CLAUDE.mdcaused by the haven-generated section thathaven apply --aiappends. Only user content outside the haven markers is compared. Previously, everyhaven statusafter an--aiapply would show the file as modified. -
Legacy
<!-- dfiles managed -->markers removed — the old pre-rename marker strings (<!-- dfiles managed start/end -->) that appeared in platform config injection have been replaced with<!-- haven managed start/end -->throughout. If your CLAUDE.md contains the olddfilesmarkers, runhaven apply --aito migrate to the new format. (CLAUDE.md is now fully managed byhaven apply --aivia a single unified section; the old dual-section approach is gone.)
[v0.7.6] — 2026-03-26¶
Added¶
-
runneraccepts an array — therunnerfield inai/config.tomlnow accepts either a string or an array, letting you invokeagent-skills-clivia a package runner without a global install:toml [skills] backend = "agent-skills" runner = ["bunx", "agent-skills-cli"] # or ["npx", "agent-skills-cli"] runner = "skills" # string shorthand still works -
haven upgradesudo fallback — when the upgrade binary write fails with a permission error (e.g. haven is installed in/usr/local/bin), the command now detects this, prints a clear message, and asks:error: Permission denied writing to /usr/local/bin/haven. Retry with sudo? [y/N]If you confirm, it runssudo mv+sudo chmod 755to complete the install. The download and checksum steps are not repeated. The extracted binary is staged in/tmprather than a sibling.newfile, so the permission error is caught at the move step rather than the extract step.
Fixed¶
haven ai backendsno longer silently shows native — previously, any error loadingai/config.toml(e.g. a parse error or missing file) would silently fall back to the native backend, making it appear as the active backend even when another was configured. The error is now propagated so you see what went wrong.
[v0.7.5] — 2026-03-26¶
Added¶
- AgentSkills backend — new
backend = "agent-skills"inai/config.tomldelegates skill fetch and deployment to agent-skills-cli. Gives access to 175K+ marketplace skills with cross-agent deployment (-aflag). Requiresnpm install -g agent-skills-cli(Node.js 18+). Haven retains full control of CLAUDE.md generation,state.jsonownership, and collision detection. Configuration:toml [skills] backend = "agent-skills" runner = "skills" # default; accepts full path to binary timeout_secs = 120 # defaultSearch (haven ai search) routes to the agent-skills marketplace when this backend is active.
Removed¶
- SkillKit backend — the
skillkitbackend has been removed. Thenativebackend remains the only supported backend. Anyai/config.tomlwithbackend = "skillkit"will error with an "unknown skill backend" message; remove that line or setbackend = "native"to continue.
[v0.7.1] — 2026-03-26¶
Fixed¶
hv upgradechecksum verification — the upgrade command was requestingSHA256SUMSbut the release workflow publisheshaven-vX.Y.Z-SHA256SUMS. This caused all self-upgrade attempts from v0.7.0 to fail with a 404 error.
[v0.7.0] — 2026-03-26¶
Added¶
-
Conflict detection —
haven apply --filesnow detects when you've edited a deployed file since the last apply and asks what to do:[s]kip,[o]verwrite,[A]pply all, or[d]iff(view a diff before deciding). Haven records a SHA-256 fingerprint of every file it writes, so it can tell the difference between "I updated this in source" and "you edited this live copy". The--on-conflict=<mode>flag skips the prompt:skip(CI-friendly, exits 1 when anything was skipped),overwrite(always clobber), orprompt(default on a TTY). -
Cmarker inhaven status— files you've edited since the last apply now show aCmarker. Combined with the source-drift marker:MCmeans both the source and your live copy have diverged. Runhaven statusbeforehaven applyto see exactly what you've locally modified.
[v0.6.0] — 2026-03-24¶
Added¶
-
Swappable skill backends — the AI skills pipeline now delegates to a configurable backend. Configure via
ai/config.toml:toml [skills] backend = "native" # defaultExisting repos need no changes — thenativebackend is the default. -
haven ai backends— new subcommand that lists all known backends with availability status and the currently active backend marked. -
docs/reference/skill-backends.md— new reference page covering the native backend configuration.
[v0.5.5] — 2026-03-24¶
Added¶
- Brewfile auto-sort — set
[homebrew] sort = truein any module config to keep the Brewfile sorted alphabetically after everyhaven brew installorhaven brew uninstall. Each kind (tap,brew,cask) is sorted independently; blank lines and comments are preserved in place. haven applyBrewfile summary — the apply summary now reports how many Brewfiles were run:Applied N file(s), M Brewfile(s) across K module(s).haven statusimprovements — the profile name is now printed at the top of status output. A✓ Everything up to datemessage is shown when no drift is found.haven importsymlink warning — after importing from chezmoi, a summary of all importedsymlink_entries is printed with a reminder to verify symlink targets before runninghaven apply.- Documentation site — full MkDocs documentation at johnstegeman.github.io/haven, covering concepts, task-oriented guides, a reference section, and a dedicated "For chezmoi Users" section. Deployed automatically via GitHub Actions.
Fixed¶
- Symlink idempotency —
haven applyno longer re-writes a symlink that already points to the correct target. Previously it would overwrite and count the file even when nothing changed. - Dangling symlink backup —
haven applyno longer attempts to back up a dangling symlink (one whose target has been deleted) before overwriting it.std::fs::copyfollows symlinks and would fail; the dangling link is now removed directly. brew bundle installoutput — spuriousUsing <formula>lines frombrew bundleare now suppressed. Output is streamed in real time instead of being buffered until completion.- Unused import — removed unused
serde_yamlimport inchezmoi.rs.
[v0.5.0] — 2026-03-23¶
Added¶
haven apply --zap— when removing unreferenced casks, also delete their associated app data and support files (brew uninstall --cask --zap). Implies--remove-unreferenced-brews.haven telemetry --action/--bug/--question "<text>"— typed telemetry annotations with auto-generated, sequenced IDs (A000001,B000001,Q000001). The ID is printed after the command so you can reference it in follow-up notes. Complements--note(which usesNprefix).haven telemetry --list-notes/--list-bugs/--list-actions/--list-questions— filter the telemetry log to a specific annotation kind.haven list— rewritten to show files, Homebrew packages, and AI skills in a unified view.[files],[brew], and[ai]section headers appear when no filter is active.--files,--brews, and--aiflags scope the output to one section.--profile <p>scopes to a specific profile.haven status --brews— now shows both missing packages (?) and packages installed but not in any Brewfile (+), giving a unified install/extra drift view in one pass.
Fixed¶
haven applyfile counter (B000002) — theApplied N file(s)summary now counts only files actually written. Previously it counted every entry processed, including files silently skipped because the destination was already identical to the source.haven apply --brews— now runsbrew bundle installfor the master Brewfile and every active module Brewfile. Previously only the masterbrew/Brewfilewas used, silently ignoring module-level packages.brew leavestap-qualified names —haven status --brewsandhaven apply --remove-unreferenced-brewsno longer report tap formulae (e.g.qmk/qmk/qmk) as extra when their short name (qmk) is declared in a Brewfile. Matching is now done by short name in both directions.haven brew install— when there is no masterbrew/Brewfilebut exactly one module Brewfile exists, it is used automatically. If multiple module Brewfiles exist and--moduleis not given, haven errors with a clear hint.haven init— scaffold always appends a[profile.default]section tohaven.tomlif one is not present, so barehaven applyworks out of the box.- Removed
--no-lockfrombrew bundle install— the flag was removed from modern Homebrew and caused an error on recent versions.
[v0.4.0] — 2026-03-23¶
Breaking¶
- Project renamed from
dfilestohaven— the binary, config file, state directory, and all environment variables have changed:
| Before | After |
|---|---|
dfiles (binary) |
haven |
dfiles.toml |
haven.toml |
~/.dfiles/ |
~/.haven/ |
DFILES_DIR |
HAVEN_DIR |
DFILES_VCS |
HAVEN_VCS |
DFILES_TELEMETRY |
HAVEN_TELEMETRY |
DFILES_PROFILE |
HAVEN_PROFILE |
GitHub repo johnstegeman/dfiles |
johnstegeman/haven |
The source encoding (dot_, private_, .tmpl, etc.) and repo layout are
unchanged — existing repos continue to work by moving dfiles.toml →
haven.toml and ~/.dfiles/ → ~/.haven/.
Added¶
config/ignoreis now a Tera template — the ignore file is rendered against the current machine context (os,hostname,username,profile,data.*) before patterns are evaluated. This matches how chezmoi treats.chezmoiignore: conditional patterns like{% if os == "macos" %}.DS_Store{% endif %}work as expected. If rendering fails, haven warns and falls back to ignoring nothing. (haven import --from chezmoinow converts Go template syntax in.chezmoiignoreto Tera syntax rather than stripping template lines.)
Fixed¶
haven initin an already-initialised repo no longer errors — it prints an informational message and exits 0. The VCS resolution prompt (Jujutsu vs Git) now only runs when a source URL is provided, not during a blank scaffold init.haven --versionnow shows the full<semver>+<short-commit>build identity (e.g.0.4.0+abc1234), matching the version field written to telemetry events.
[v0.3.0] — 2026-03-23¶
Security¶
- Fixed HIGH: tarball symlink traversal in
extract_tarball— a maliciousgh:skill package could plant a symlink entry pointing outside the cache directory, then write a file through it on extraction. Symlink and hard-link tar entries are now unconditionally skipped before extraction. Users on v0.2.0 who fetch skills from untrustedgh:sources should upgrade before runninghaven apply. See.gstack/security-reports/2026-03-23.jsonfor the full audit record.
Added¶
haven security-scan— audit all tracked source files for secrets, sensitive filenames, and credential paths. Checks filename patterns (.env,id_rsa,.pem…), sensitive paths (~/.aws/credentials,~/.kube/**,~/.ssh/**…), and content patterns (GitHub tokens, AWS keys, PEM private keys, OpenAI/Anthropic API keys, generic password assignments). Optional--entropyflag adds high-entropy string detection. Exits 1 when findings are found (CI-friendly). False positives suppressed via[security] allowinhaven.toml.haven addcontent scan — when adding a file, its content is automatically scanned for secrets. A prompt is shown before saving; declining removes the file fromsource/with no partial state left behind.haven completions <shell>— print shell completion scripts to stdout. Supportsfish,zsh, andbash. All subcommands and flags are included.haven list— list all tracked files with decoded destination paths and flag annotations (template,private,symlink,extdir,extfile, etc.).haven telemetry— manage local telemetry from the CLI.--enable/--disableflip[telemetry] enabledinhaven.tomlusing surgicaltoml_edit(preserves comments and formatting).--note "<text>"appends a{"kind":"note"}entry to~/.haven/telemetry.jsonlregardless of whether telemetry is enabled — useful for annotating test runs, onboarding sessions, or observed issues so the log has context during analysis. Barehaven telemetryprints the current enabled/disabled status.haven upgrade— self-update command. Downloads the latest release tarball from GitHub, verifies the SHA256 checksum, extracts the binary, and atomically replaces the running executable.--checkflag exits 0 when up to date, 1 when an update is available (CI-friendly). Supports macOS (arm64, x86_64) and Linux (x86_64, aarch64, armv7, i686 musl).- Jujutsu (jj) VCS backend — configure haven to use
jj git clone --colocatefor all new clone and init operations. Set via--vcs jjflag,HAVEN_VCS=jjenv var, or[vcs] backend = "jj"inhaven.toml. On first use without a config, haven detects whether jj is on your PATH and prompts once.haven vcsshows the active backend and how it was resolved. haven unmanaged— walk~and report files not tracked by haven. Only dotfiles and dotdirs are examined at the home root. High-noise directories (.cache,.cargo,node_modules,.git,Library, etc.) are skipped.--path <dir>scans a specific directory;--depth <n>controls recursion depth (default: 3). Useful for discovering dotfiles to add.[data]custom template variables — define arbitrary string variables inhaven.tomlunder[data](e.g.host = "my-laptop"). Available in all.tmplfiles as{{ data.host }}.haven import --from chezmoiautomatically migrates.chezmoidata.yaml/.chezmoidata.tomlinto[data]entries.haven dataprints all resolved variables.haven data— show all template variables in scope: built-in variables (os,hostname,username,home_dir,source_dir) and custom[data]entries fromhaven.toml. Useful for debugging templates.config/ignorewarning onhaven add— if a file being added matches an ignore pattern, the add is skipped with a clear message explaining how to remove the pattern.
Added (docs)¶
docs/from-chezmoi.md— getting started guide for chezmoi users. Covers the automated migration path, template syntax conversion table, command equivalence table, Brewfile/module/profile setup, AI skill import, new-machine bootstrap, daily workflow comparison, and a gap table of chezmoi features not yet in haven.
Fixed¶
- Installer URL typo (affected the guide; the binary download URL was correct).
- Pre-existing build warnings: unused import and dead code in internal modules.
[v0.2.0] — 2026-03-21¶
Added¶
haven ai add-local— import a locally developed skill directory into the haven repo. Moves the skill intoai/skills/<name>/files/, writesskill.tomlwithsource = "repo:", creates a blank snippet stub, and removes the original directory. Runhaven apply --aiafterward to deploy.extfile_source encoding — track single-file and archive remote downloads insource/. Two types:type = "file"(plain download) andtype = "archive"(tarball extract with optional subpath). SHA-256 verification supported.haven diffshows?when the destination is absent.haven ai search— search the skills.sh registry for available skills. Results show source ingh:owner/repo/skillformat and install count.haven ai scan— scan an existing skills directory for unmanaged skills and offer to add them toai/skills.toml. Detects source via git remote or skills.sh fuzzy search.- Managed config section injection —
haven apply --aiinjects skill snippets fromall.md/<platform>.mdinto platform config files (e.g.~/.claude/CLAUDE.md) between HTML comment markers. Idempotent. haven diff --ai— shows stale skill SHA drift and missing deployments.haven diffextdir ref drift — shows when a cloned external repo is behind the pinnedrefin the marker file.haven.lockSHA verification — on cache miss, the freshly-fetched SHA is compared against the lock entry. Mismatch is a hard error; runhaven ai updateto accept intentional upgrades.- Parallel skill fetches —
haven apply --aifetches multiplegh:skills concurrently usingstd::thread::scope. A single miss fetches inline; 2+ prints "Fetching N skills in parallel…" with per-skill results. - Apply file lock — writes PID to
~/.haven/apply.lockto prevent concurrent runs. Stale locks (dead PID) are cleaned up automatically. haven source-path— print the repo directory path. Useful in scripts and shell aliases.- XDG default repo directory — new installs default to
~/.local/share/haven. Existing~/havenrepos are still detected and used without migration. haven add --update— re-copy a file intosource/even if already tracked.home_dirtemplate variable — available in.tmplfiles alongsidehostname,username,os, etc.create_prefix support —create_files are written on apply only if the destination does not already exist.exact_directory prefix — on apply, files in the destination that are not tracked insource/are removed (backed up first).- Script execution —
haven apply --run-scriptsruns scripts fromsource/scripts/.run_once_/once_scripts are tracked in state and skipped on subsequent runs. - Opt-in local telemetry — disabled by default. When enabled, events are
written to
~/.haven/telemetry.jsonl(command name, flags, duration, exit status — no paths or personal data).
Fixed¶
modify_scripts in chezmoi import now emit a clear skip message with guidance instead of silently disappearing.- Config structs use forward-compatible deserialization (unknown fields are ignored rather than erroring).
[v0.1.0] — 2026-03-20 (initial release)¶
Added¶
haven init— create a blank scaffold or clone an existing haven repo. Supportsgh:owner/repo[@ref]shorthand,--apply,--profile,--branch.haven add— track a dotfile by copying it intosource/. Sensitive filename detection prompts before saving. Directory add: recursively adds files or tracks the directory as anextdir_external git clone.haven apply— copy source files to their destinations, install Homebrew packages viabrew bundle, run mise, deploy AI skills.--dry-runmode,--files/--brews/--aisection filters,--remove-unreferenced-brews,--interactive,--apply-externals,--run-scripts.haven diff— show file-level diff betweensource/and live files.--stat,--color,--profile,--moduleflags. Exit 1 on drift.haven status— concise drift summary with✓ M ? !markers.haven brew install/uninstall— run brew operations and keep Brewfiles in sync in one step.haven import --from chezmoi— migrate from chezmoi. Handlesdot_,private_,executable_,symlink_prefixes; converts Go templates to Tera; imports.chezmoiexternal.tomlgit entries asextdir_markers; imports.chezmoiignoreasconfig/ignore.haven ai add/fetch/update/remove/discover— manage AI agent skills across platforms. Skills declared inai/skills/<name>/skill.toml, fetched fromgh:owner/repo[@ref], pinned by SHA inhaven.lock.- Magic-name file encoding —
dot_,private_,executable_,symlink_,extdir_,.tmplsuffix. Compatible with chezmoi's encoding. - Tera templates —
.tmplfiles rendered withhostname,username,os,arch,env,profile,source_dirvariables. - 1Password integration —
{{ op(path="op://vault/item/field") }}template function reads secrets at apply time. - Profiles —
[profile.<name>]inhaven.tomlwithmoduleslist and optionalextendsinheritance. - Modules — group Homebrew packages and mise configs.
--moduleflag onapply/diffto scope package operations. extdir_externals — track remote git repos as clone markers; cloned onhaven apply.- Cross-platform binaries — macOS (x86_64, arm64) and Linux (x86_64, aarch64, i686, armv7 musl).
- Shell installer —
curl -fsSL .../install.sh | shwith SHA256 verification and automatic PATH detection.