Documentation
¶
Overview ¶
D is the dead config linker. It links regular files from a source tree into a target tree.
It is a small command for linking filesystem-shaped source trees by symlink. The source tree is the manifest. The destination tree is the filesystem. D does not care what made the source directory. It can be a Git repo, tarball, copied folder, generated tree, mounted disk, or anything else that appears as a filesystem tree. There is no database, no templating pass, no bootstrap ritual, and no hidden state to debug at 2 a.m.
D plans before it mutates anything. If the plan contains a conflict, D prints the plan and exits without changing the filesystem. That is the contract.
Usage ¶
d [flags] [source]
If source is omitted, D reads the current directory. If -t is omitted, D uses the home directory reported by the operating system. The -t flag takes a real path; D does not expand shell syntax such as ~ or $HOME. Pass those values expanded by your shell, or quote them if you want them treated literally.
The flags are:
-p Print the plan without changing the filesystem. -u Unlink managed symlinks. -i Replace an existing destination symlink with the source link instead of reporting it as a conflict. It cannot be combined with -u. -x pattern Exclude an additional source path. The flag may be repeated. A pattern without a slash matches any path component. A pattern with a slash matches the slash-separated relative path. -t path Set the target root. -l name Set the source layout. The supported layouts are flat and platform. The default is flat.
Layouts ¶
In flat layout, D walks source directly. Every regular file below source maps to the same relative path below the target root. This is the default layout.
For example:
source/.gitconfig -> $HOME/.gitconfig source/.config/nvim/init.lua -> $HOME/.config/nvim/init.lua
In platform layout, D walks source/GOOS, where GOOS is the current Go operating system name, such as linux, darwin, windows, or plan9.
For example, on Linux:
source/linux/.gitconfig -> $HOME/.gitconfig source/linux/.config/nvim/init.lua -> $HOME/.config/nvim/init.lua
Use flat layout for a tree that already looks like the destination tree. Use platform layout when one source tree contains separate per-OS trees.
Files ¶
D only links regular source files. It walks directories, ignores empty directories, and rejects source symlinks and other non-regular entries. Destination paths are computed as:
destination = target root + source relative path
D creates missing parent directories with mode 0700. It creates symlinks to absolute source paths. It leaves an existing correct symlink alone. It refuses to overwrite ordinary files, directories, and symlinks that point somewhere else, unless -i is set for an existing symlink.
D treats managed symlinks by exact link text. A symlink that reaches the same file through a relative path, ., .., or another filesystem alias is still a conflict unless its stored target text is exactly the expected absolute source path.
D orders planned actions by destination path. Duplicate destination detection is textual; D does not try to merge paths that only collide through filesystem-specific aliases.
The default excludes are deliberately boring. At any depth, D ignores:
.git .hg .DS_Store Thumbs.db *.swp *~
At the source root only, D ignores:
README README.* LICENSE LICENSE.* COPYING COPYING.*
D treats the source as a filesystem directory. It does not require repository awareness, package metadata, VCS history, or any other tool-specific structure. It reads directory entries and file metadata from the filesystem, then applies the layout and exclude rules above. The built-in excludes only skip a small set of common metadata and junk paths. Use -x for any other metadata your tree carries.
Target Roots ¶
The target root must be explicit when the source tree looks like a filesystem root. For example, a flat source tree containing top-level directories such as etc, home, usr, var, Users, ProgramData, or rc can be real system configuration, not a home-directory tree. D refuses to guess.
Use -t / for a root filesystem deployment. Use -t "$HOME" when you want the home directory and the source tree happens to look root-shaped.
When targeting /, spell home paths fully. If the real home is /home/alice, write home/alice/.config/app, not home/.config/app.
Unlink ¶
With -u, D removes only managed symlinks: links whose destination path matches the source tree layout and whose link target points exactly at the expected source file. If the source tree has already been removed, D can still scan the target root for exact managed links using the source path that would have been used for the current run. It does not delete regular files. It does not clean up directories. It does not guess.
Safety ¶
D rejects source and target roots that are symlinks or have symlink ancestors. The target root must already exist and must not be inside the active source tree.
A conflict prevents all filesystem mutation. Operational failures during execution are not transactional; D reports the error and does not roll back earlier successful operations from the same run.
On Linux and Android, D uses openat2-based target operations to reject symlink resolution, magic links, and filesystem boundary crossings under the target root. On other supported platforms, D uses the standard library rooted filesystem operations available to Go.
When D needs to create parent directories or replacement symlinks, it tries to preserve ownership from the nearest existing parent directory on platforms that expose that metadata. If the operating system refuses symlink creation, D returns that error instead of switching to a weaker link type.
Examples ¶
d /path/to/source d -l=platform /path/to/source d -t /tmp/stage -p system d -x .cache -x private /path/to/source d -u /path/to/source d -p -u /path/to/source d -i /path/to/source d -t "$HOME" /path/to/source
Output ¶
D writes human-readable action lines to standard output. Errors go to standard error.
Typical actions are:
LINK /home/alice/.gitconfig -> /home/alice/source/.gitconfig OK /home/alice/.config/nvim/init.lua IMPORT /home/alice/.ssh/config: symlink points to /old/config -> /home/alice/source/.ssh/config CONFLICT /home/alice/.ssh/config: regular file exists UNLINK /home/alice/.config/nvim/init.lua MISSING /home/alice/.config/nvim/init.lua
The exit codes are:
0 success 1 conflict or operational error 2 invalid usage