Tracking Files

Adding files

haven add ~/.zshrc
haven add ~/.gitconfig
haven add ~/.config/git/config

haven copies the file into source/ with its destination path and metadata encoded in the filename. Permissions are auto-detected: a file with mode 0600 gets private_ prefix, executable bits get executable_ prefix.

Re-adding a changed file

haven add ~/.zshrc --update

Without --update, adding an already-tracked file is an error.

haven add ~/.config/vscode/settings.json --link

On apply, the destination is symlinked back into source/ rather than copied. Use this for files that applications manage themselves — symlinks mean the app's writes go directly into your repo.

Adding directories

haven add ~/.config/nvim

If the directory is a git repository with remotes, haven prompts you:

~/.config/nvim is a git repository with 1 remote:

  1) origin   https://github.com/user/nvim-config

How to add?
  1) Add as external (cloned on apply)
  f) Add all files recursively
  q) Skip
[1/f/q]:

Choose external to track it as an extdir_ entry (re-cloned on apply) or files to copy everything recursively.

Stopping tracking

haven remove ~/.zshrc
haven remove ~/.zshrc --dry-run    # preview first

Deletes the source/ copy. The live file on disk is not touched.

Viewing tracked files

haven list                # all tracked files, packages, and skills
haven list --files        # files only

Output shows file annotations in parentheses:

~/.zshrc
~/.gitconfig          (template)
~/.ssh/config         (private)
~/.local/bin/delta    (extfile)
~/.config/nvim        (extdir)
~/.vimrc              (symlink)

Ignoring files

Create config/ignore in your repo root to exclude files from apply, status, and diff:

# config/ignore

# Skip a specific file
.zshenv

# Glob patterns
.ssh/id_*
.config/*/history

# Match everything under a directory
.local/share/some-app/**

# Negate a previous match (un-ignore)
!.local/share/some-app/keep-this

config/ignore is a Tera template, so you can use conditionals:

{% if os == "macos" %}
.DS_Store
{% endif %}

# Always ignored
.ssh/id_*

Pattern rules

Syntax Meaning
# at start Comment
* Any non-/ characters
** Any characters including /
? Any single non-/ character
! prefix Negate — un-ignores a previously matched path
Pattern with no / Matches basename only
Pattern with / Matches full path from home root

Finding untracked files

haven unmanaged                   # scan ~ up to depth 3
haven unmanaged --path ~/.config  # scan a specific directory
haven unmanaged --depth 5         # scan deeper

Skips noisy directories automatically (caches, .git, node_modules, etc.). Use the output to decide what to start tracking:

haven unmanaged | head -10
haven add ~/.config/bat/config

External git repos (extdir_)

External directories are git repos that haven clones into your home directory — plugin managers, separate config repos, etc. They live as extdir_ marker files in source/.

Example

source/dot_config/extdir_nvim

Content of the marker file:

type = "git"
url  = "https://github.com/user/nvim-config"
ref  = "main"   # optional: branch, tag, or commit SHA

On apply, haven clones this repo into ~/.config/nvim.

Apply behavior

State What happens
Destination absent git clone [--branch ref] url dest
Destination is a git repo Skipped (use --apply-externals to pull)
Destination is not a git repo Error — remove manually first
haven apply --apply-externals    # also pull existing clones