Files
command-center/agent/managed-skills/dotfiles-adoption-audit/SKILL.md
T
Frank 8af40c402b chore(agent): commit the machine tier and the doctrine text the checkout was already running
Landing blocker for #61 and #63: the deployment checkout is 12 commits behind and
`merge --ff-only` refuses while tracked paths are dirty. Discard is not available here
(workspace policy: no `checkout`/`stash` on shared state), so the dirt is committed.

- `agent/APPEND_SYSTEM.md`: the point-of-use / one-work-log / PR-link doctrine, already
  byte-identical to `origin/main` (`cmp` against the trunk blob: no difference). No new
  prose — the commit exists so the trunk merge can proceed.
- `agent/config.yml` and `agent/managed-skills/**`: the machine-live tier the heartbeat
  owns (AGENTS.md § Live-sync tiers).

`ALLOW_SECRETS=1` was used, deliberately and after auditing the staged diff by hand: the
only credential-shaped strings in it are two copies of `AKIA0000000000000EXAMPLE` — the
inert all-zero AWS example id — and they appear inside the two skill pages that teach
that exact placeholder shape. This checkout is still running the pre-#61 hook; the merged
gate (value-scoped placeholder filter, `71601f7`) exempts this value, so the refusal
dies with this landing. No `--no-verify` was used: the gate ran and its verdict is
recorded here.

Refs #61
2026-10-21 01:44:51 -07:00

4.1 KiB

name, description
name description
dotfiles-adoption-audit Use when deciding which userspace configs on a Dank box belong in the command-center dotfiles tier — separates tracked intent from generated expansion, app state, secrets, and config owned by another repo. Not for deploying one known file.

Dotfiles adoption audit

Decides, with evidence, which files under ~/.config (and top-level dotfiles) belong in dank/command-center's dotfiles/ tier. The repo law being applied: config in, state out, and one fact, one owner.

The four gates (all four must pass)

  1. Installed? command -v <prog> — config for software absent from the box is a prune candidate, never an adoption target. This eliminates most of the clutter.
  2. Authored, or the expansion of something else? Generated files must stay out even though they look like config.
  3. Does another repo or installer already write it? If a script or package owns the file, tracking it here creates a second owner that loses every argument.
  4. Could a secret ever live in it? If yes: template + quarantine, or leave it out.

Gate 2 is the one people get wrong — prove generation from mtime

A generator walking the app list writes dozens of files in the same sub-second window. Compare timestamps across unrelated programs:

cd ~/.config && stat -c '%y  %n' */themes/noctalia* */noctalia.* */colors/noctalia* 2>/dev/null | sort

Identical seconds + microsecond progression across ten different programs = generated. Re-check one file days later: a new mtime with no human edit proves regeneration, so the tracked file must be the source (palette/config the generator reads), never its output. The correct pattern is a tracked config that imports the generated path.

Classify the whole tree per file, not per directory

The tracked unit is the file symlink, so a directory can be "real" while containing only tracked symlinks. Never classify by directory:

cd ~/.config && for d in */; do d=${d%/}; tr=0; rl=0; rlfiles=""
  while IFS= read -r f; do
    case "$(readlink -f "$f" 2>/dev/null)" in
      */.omp/dotfiles/*) tr=$((tr+1));;
      *) rl=$((rl+1)); rlfiles="$rlfiles ${f#./}";;
    esac
  done < <(find "$d" -maxdepth 2 \( -type f -o -type l \) 2>/dev/null \
           | grep -vE 'Cache|cache|Cookies|storage|sessions|Crashpad|Default|thumbnails|extensions')
  [ $((tr+rl)) -eq 0 ] && continue
  printf '%-22s tracked=%-3s box-only=%-3s %s\n' "$d" "$tr" "$rl" "$(echo $rlfiles | cut -c1-90)"
done

Then read the headers of suspicious files — installers often confess ("Installed by infra/setup-dev.sh into ~/.config/containers/systemd/") and unit files name another project's WorkingDirectory/ExecStart, which means that project owns them.

Ownership before adoption

git -C ~/.omp ls-files dotfiles                  # packages deploy.sh sees
grep -rl "<unit-or-file-name>" ~/Projects/<proj> # does a project repo own it?
systemctl --user is-active <unit>                # dead config is not load-bearing

Secret-gap check (do this before adopting anything env-shaped)

The ignore list may cover only .env, so frank-job-hunt.env / postgres.env fall through, and a token-shape secret gate (sk-, ghp_, PEM, JWT) does not match a low-entropy POSTGRES_PASSWORD=…. Test both explicitly:

cd ~/.omp && git check-ignore -v --no-index 'dotfiles/x/postgres.env' || echo "NOT IGNORED"
sed -n 's/^patterns=//p' .githooks/pre-commit

Fix = add *.env to the quarantine block and a password-assignment pattern to the gate, with a red test that stages a fake POSTGRES_PASSWORD= file.

Land it

Packages are home-relative trees under dotfiles/<pkg>/; per-host overrides go in zz-$(hostname) (stowed last). dconf is loaded via dconf load /, systemd-user gets daemon-reload + conditional enable --now. Sequence: scripts/deploy.sh --check (dry run, reports divergents) → adopt → deploy.sh → confirm live paths are symlinks into the repo → bats tests/ (includes the real-bundle kb-lint/coverage gate) → branch off origin/main, PR to main, never merge without Frank's OK.