- Shell 56.6%
- Python 18.7%
- Ruby 13.6%
- Lua 9.1%
- CSS 1.1%
- Other 0.9%
- `--version 6.4.1` installs that exact toolchain and makes it the global
default. "latest" moves, while a project can pin one in .swift-version, and
swiftly's `swift` refuses to run anywhere under that file when the pinned
version is missing.
- A false OK is fixed. With `swift` on PATH, the script took the proxy's
refusal ("The swift version file … uses …") as the version, printed
"already on PATH — skipping install" and exited 0, so nothing was
installed. The default is now asked from `/` (a pin in the caller's
directory cannot decide it) and only a successful `swift --version`
counts, in the skip check, --check and the final verify. With --version,
the final verify also requires that version.
- `--deps` printed "Dependencies installed." and exited 0 even when
apt-get failed (seen on a box whose sudo needs a password, 2026-10-16).
It now says so only on success; otherwise it prints FAILED and exits 1.
The failing path is not exercised here, because builder's sudo is
passwordless.
Unchanged elsewhere: no --version means latest, as before; a box with a
working swift still skips; macOS is still a no-op. Run on builder: --check
reports the real default (6.3.3) where it reported the refusal text, and
`--version 6.4.1` installed 6.4.1 as the default ("Done: Swift version
6.4.1").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|---|---|---|
| .claude | ||
| bin | ||
| doc | ||
| docs | ||
| home | ||
| lib | ||
| recipes | ||
| .gitignore | ||
| .nvim.lua | ||
| .nvimlog | ||
| CLAUDE.md | ||
| install | ||
| Makefile | ||
| readme.md | ||
Installing the environment
curl -sSL https://gurgul.pro/artur/environment/raw/branch/main/install | bash
Config:
| Variable Name | Default Value | Description |
|---|---|---|
DAT_CACHE_PATH |
${HOME}/.cache/dat/ |
Path where cached data is stored. |
DEFAULT_INTERNET_LOGIN |
not set | |
DAT_VM_DATA |
${DAT_CACHE_PATH}/vm |
Directory for storing VM-related data. |
Installing build daemon
make install-daemon
Dependencies — dat --install
The tools the shell and editor configuration in home/ depend on are
installed by scripts, never by hand, and one command runs them:
| Command | Effect |
|---|---|
dat --install |
install or update the default dependency set |
dat --install <name> |
just one, e.g. dat --install fzf |
dat --install --all |
include the desktop-only ones (fonts, Zed, printup) |
dat --install --list |
what is registered, and which are in the default set |
dat --install --check |
report what is installed — installs nothing |
dat --install --forced |
reinstall even where the tool is already present |
Every entry is a script under home/.local/bin/, registered in
Install::DEPENDENCIES (lib/install.rb). Each is idempotent, so a
re-run on a provisioned box skips rather than rebuilds. dat install
and dat update go through the same register.
The default set is fzf, rust-tools (bat, fd), nvim and swift —
what home/.zshrc and the Neovim config actually need in order to behave
as written. fonts, zed and printup are real dependencies of a
desktop box but not of a headless one, so they are opt-in.
fzf is not optional here: wd --find, v --open, the gf and
hist aliases and bin/index-notes-deprecated (was bin/index; index
is now the monorepo's Swift file indexer) are all built on it. If v --open prints
"no fzf — 'wd --list' shows the projects without it", the fix is
dat --install fzf.
macOS host config — dat macos
dat macos --setup # personal defaults (settings, dock) + unattended-boot posture
dat macos --check # is the unattended-boot posture in place? (exit 0/1)
dat macos --status # full state dump
dat macos --defaults # just settings + dock
The unattended-boot posture — FileVault off, auto-login, no lock screen,
passwordless sudo, firewall on — is for a VM/host you fully control, where
the console is the credential and the network surface is closed. Read
bin/macos-config/README.md before running --setup.
Prompt width — mps
The zsh prompt has three widths, for when you drop onto a phone or a small
terminal. Defined in home/.zshrc, switched with the mps function:
| Command | Prompt |
|---|---|
mps full |
user@host ~/full/path (branch) ➜ (default) |
mps git |
dir (branch) ➜ — minimal, keeps git info |
mps static |
➜ — minimal, no git, no vcs_info cost |
mps |
no argument → cycle full → git → static → full |
mps status |
print the active mode |
The choice is saved to ~/.projps and restored by the next shell.
Test: bin/test-mps.
Workdir jump — wd / v
wd gets you into the workdir monorepo and its subprojects fast; v
opens Neovim there. Both defined in home/.zshrc.
| Command | Effect |
|---|---|
wd |
cd to the workdir root — /workdir on Linux, /opt/workdir on macOS ($WORKDIR overrides; an existing path is preferred) |
wd --find |
fzf-pick a project by name / description and cd into it |
wd -f |
alias for --find |
wd --list |
print the project table, no picker (works without fzf) |
wd --help |
usage |
v [files…] |
open Neovim (plain passthrough — replaces the old alias v=nvim) |
v --open |
fzf-pick a project the same way and start Neovim with it as the working directory; the shell's own cwd is left alone |
v -o |
alias for --open |
A project is any directory holding a .nvim.lua marker. Its name and
one-line blurb come from that file:
return { name = "hiot-hub", description = "ESP32 Hub firmware — ESP-NOW→MQTT bridge" }
This is the same table Neovim reads for fzf_ignore_dirs
(home/.config/nvim/lua/keymaps.lua). A marker without a name falls
back to its directory's own name. .git, .claude and node_modules
are skipped during the scan.
--find and v --open need fzf on PATH — install it with
dat --install fzf (see Dependencies).
wd --list is the fallback that works without it.
Test: bin/test-wd (covers both wd and v).
Scanning — scanup
The companion to printup: scans from a network scanner to a PDF on the
machine you run it on. It speaks eSCL (AirScan) to anything advertising
_uscan._tcp, in standard-library Python — nothing to install.
| Command | Effect |
|---|---|
scanup |
scan with the default scanner → ~/Scans/scan-YYYYMMDD-HHMMSS.pdf; the feeder if it holds paper, else the glass |
scanup --select |
pick a scanner, save it as the default, then scan |
scanup --set-default L6600 |
save a default (any unambiguous fragment of host or label) |
scanup --list-scanners |
what is on the network; * marks the default |
scanup --scan-from T520W |
this scan only, from another scanner |
scanup --adf --duplex |
both sides of every sheet in the feeder |
scanup --bw --dpi 200 |
smallest text scans (1-bit CCITT); --gray and --size letter also exist — both Brothers still send gray as RGB |
scanup -o FILE · -o DIR/ |
write elsewhere (never overwrites without --force) |
scanup --check |
Python, discovery, the default scanner, the merge tool |
The default lives in ~/.config/scanup/default_scanner, the same two-line
shape as printup's. A feeder job that the scanner returns as one document per
page is merged with pdfunite or qpdf when present; without either, the
pages are kept as numbered files and --check says how to add one.
Traps and measurements: docs/lessons-learned.md.
Test: bin/test-scanup (--live scans the glass of each scanner found).
Repository autosave — gitd-updater
A systemd timer that, every minute, commits / pulls / pushes registered repositories so work in progress is never stranded on one disk. Debian only — it is built on systemd system units and refuses to install elsewhere.
| Command | Effect |
|---|---|
sudo gitd-updater --install |
install the units and start the timer (runs as you) |
gitd-updater --add /workspace |
register a repository (not with sudo) |
gitd-updater --list |
registered repos, failure counts, suspensions |
gitd-updater --check |
verify the install, and that the remote is reachable the way the unit reaches it |
gitd-updater --resume [PATH] |
clear a suspension by hand |
sudo gitd-updater --uninstall |
remove the units; registry and state are kept |
A submodule you are actively editing (uncommitted changes newer than an hour) is held untouched; older ones are committed and pushed to their own remote before the parent's gitlink moves. Conflicts abort cleanly and retry; after five consecutive failures a repo is suspended for an hour, then retried automatically.
Full description, policy table and traps: doc/gitd-updater.md.
Test: bin/test-gitd-updater (--selftest first — it proves the harness can fail).