Configuration¶
Root Configuration¶
over supports a root configuration file at ~/.over/over.toml (or
over.yaml/over.yml). This file controls global preferences that apply
across all overlays.
Format Preference¶
The format field sets the default descriptor format used by over new
when creating new overlays. Accepted values are toml (default) and yaml.
TOML (~/.over/over.toml):
YAML (~/.over/over.yaml):
Format resolution priority (highest to lowest):
--format/-fCLI flag- Root config
formatfield - Default (
toml)
This preference only governs what over new writes. Reading an overlay
tolerates any of .toml/.yaml/.yml regardless of this setting — see
ADR-003.
Default Overlay Selection¶
The default_overlay field names the overlay commands should act on when
no NAME argument is given. It's rendered as a template against the same
context used for an overlay's own target field ({{ machine.* }}, etc.),
so it can resolve to a different overlay per machine:
Selection priority (highest to lowest) for over apply/over unapply/
over commit:
- An explicit
NAMECLI argument. - The resolved
default_overlay. - The existing interactive fuzzy-select prompt.
For over status/over diff/over sync, omitting NAME normally reports
on every overlay; once default_overlay is configured, it narrows an
omitted NAME to just that overlay instead. Pass -a/--all to force
"every overlay" regardless of a configured default.
A default_overlay naming an overlay that doesn't exist, or that fails to
render, is a hard error — never a silent fallback to another selection
method. See
ADR-019.
over doctor deliberately does not participate in this:
its Overlay configuration and XDG state sections always cover every overlay
in the repository regardless of NAME, so narrowing the whole report to a
single default overlay would leave those sections inconsistently scoped
with the Git-exclude section. doctor's NAME argument only narrows which
overlay's .git/info/exclude drift gets checked; there is no --all flag.
Materialization Rules¶
By default, every file in an overlay is symlinked individually and every directory is recursed into. Two fields, available both in the repository root config and in any overlay's own descriptor (they inherit through the same cascading chain as every other field — see ADR-002), let you override this per overlay or per subtree:
[defaults]
materialization = "symlink" # symlink | symlink-directory | checkout
[[rules]]
path = "some/directory" # glob or literal, relative to the overlay root
materialization = "symlink-directory"
defaults.materializationsets the materialization applied to every directory with no more specificrulesmatch.symlink(the default) recurses into the directory and symlinks each file individually.symlink-directorysymlinks the directory as a single unit — its contents are not separately enumerated or tracked.checkoutmakes the subtree a virtual checkout — ordinary, directly editable files with no.gitat the target — see Virtual checkouts and ADR-022.rulesis a list of path/subtree overrides.pathis a glob pattern (or a literal path) relative to the overlay root. When more than one rule matches the same path, the most specific one wins: a literal path always outranks a glob, and among glob patterns the longer one wins.- A repository root
over.tomlsettingdefaults/rulesbecomes the baseline for every overlay; any overlay along the cascading chain can override either field entirely for its own tree (the nearest descriptor that defines the field wins, same asexclude/link_dirs/git/uses). - A file added to a source subtree still governed by a
symlink(file-level) rule is automatically picked up the next timeoverinspects the overlay — there is no separate step to "add" it to the rule.
link_dirs (a list of glob patterns symlinked as a whole directory instead
of walked file-by-file) still works and is equivalent to a rules entry
with materialization = "symlink-directory" — both resolve through the
same mechanism. See ADR-017.
File Permissions¶
defaults.mode and permissions mirror defaults.materialization/rules
exactly (same cascading inheritance, same specificity precedence), but
declare a desired permission mode instead of a materialization strategy:
[defaults]
mode = "644" # octal string; applied when no more
# specific `permissions` entry matches
[[permissions]]
path = "ssh/agent" # matches a partial sidecar's own stem
mode = "600"
- Only meaningful for Partial Files — the one place
overwrites real, target-owned content directly today. Every symlinked file/directory shares its overlay source's inode: there's no independent target permission to set withoutovermutating that tracked source file, which stays out of scope (see ADR-020). pathmatches a<name>.partial.{toml,yaml,yml}sidecar's own stem (e.g.ssh/agentforssh/agent.partial.toml), not its renderedtarget.- No
permissions/defaults.modeat all (the default) leaves permissions entirely unmanaged — identical to pre-#65 behavior. - A drift (the block's content already matches, but the target's actual
mode doesn't) is auto-fixed on the next
over apply, reported byover status/over difflike any other pending change — never a blocking conflict.
Partial Files¶
A <name>.partial.{toml,yaml,yml} sidecar file, placed anywhere in an
overlay, injects a managed block into an existing (possibly foreign) file
instead of symlinking it whole — useful for a single alias, export, or
config stanza that must coexist with content over doesn't otherwise
manage.
# aliases.partial.toml
target = "~/.zshrc"
content = "alias ll='ls -la'\n"
# marker = "aliases" # optional; defaults to the sidecar's own stem
target: the file to modify. Templated the same way a.link.*sidecar'stargetis ({{ env.* }},{{ machine.* }},{{ overlays[...] }}) — not the same context as an overlay's owntargetfield, which currently only exposes{{ machine.* }}and has noenv/overlaysmaps. See ADR-010 for the templating design these two paths share.content: the literal block body, used verbatim (not templated).marker: identifies the block, so more than one sidecar can manage distinct blocks in the same target file. Defaults to the sidecar's stem.
The block is delimited by fixed #-comment marker lines:
A hand-edited block (content between the markers no longer matching what
the overlay declares) is always reported as a conflict, never silently
overwritten, exactly like any other apply conflict — see
ADR-016. over unapply removes
only the block, leaving the rest of the target file untouched.