Agent Brief
Category: bug / enhancement
Summary: While debugging a stray keychain: can't find <path>; skipping warning on LG14, an agent edited the deployed ~/.config/fish/conf.d/keychain.fish directly to fix the trigger and tweak the auto-unlock UX, without updating the tracked template at module/config/fish/conf.d/keychain.fish. This is now a confirmed drift case (same class of problem as #278, different mechanism) and needs a decision on how the tracked template should be brought back in sync — across this machine's repo checkout and any other machine (e.g. 192.168.10.10) that received the stale template via fish.module.sh's install().
Current behavior:
module/fish.module.sh's install() does cp -r "${_src}" "${HOME}/.config/fish" once; upgrade() only reinstalls fisher plugins and never re-copies the config directory. So once a machine is bootstrapped, its deployed conf.d/keychain.fish never resyncs from the repo template again — any repo-side fix (or any local drift) has no automatic propagation path in either direction.
- The originally deployed
keychain.fish (still in the repo template, unchanged) parses IdentityFile entries out of ~/.ssh/config via awk, and calls keychain --eval $keys | source (first terminal per login, gated by a $XDG_RUNTIME_DIR/keychain.shown marker) or keychain --quiet --eval $keys | source (subsequent terminals).
- Root cause of the literal warning (separate, already fixed locally, not a template bug):
~/.ssh/config on LG14 had CRLF line endings, so the awk-extracted path carried a trailing \r, and keychain's [ -f "$pm_k" ] check failed. Converting the file to LF fixed it — this was a personal dotfile issue, not something the template caused.
- Confirmed via
/usr/bin/keychain source (ssh_listmissing, ~line 1030): keychain already fingerprints the running agent's loaded keys via ssh-add -l before deciding whether to prompt, so it only invokes ssh-add (and only then shows a passphrase prompt) for keys not already loaded. The marker-file split in the template is therefore purely a verbose/quiet banner-text toggle — it has no effect on when the passphrase prompt itself appears.
What changed locally (uncommitted nowhere, deployed-file only):
~/.config/fish/conf.d/keychain.fish on LG14 was rewritten to drop the marker/verbose-vs-quiet split (functionally a no-op simplification per the above) and keep keychain --quiet --eval $keys | source unconditionally, so first-terminal-per-login still auto-prompts for the passphrase and later terminals silently share the already-unlocked agent. This matches the desired UX ("open a terminal → if the key isn't unlocked yet, prompt right there; once unlocked, every other terminal shares it"). This edit was not ported back to module/config/fish/conf.d/keychain.fish, so it is currently local-only drift on one machine.
Decision needed:
Key interfaces:
Out of scope:
Agent Brief
Category: bug / enhancement
Summary: While debugging a stray
keychain: can't find <path>; skippingwarning on LG14, an agent edited the deployed~/.config/fish/conf.d/keychain.fishdirectly to fix the trigger and tweak the auto-unlock UX, without updating the tracked template atmodule/config/fish/conf.d/keychain.fish. This is now a confirmed drift case (same class of problem as #278, different mechanism) and needs a decision on how the tracked template should be brought back in sync — across this machine's repo checkout and any other machine (e.g.192.168.10.10) that received the stale template viafish.module.sh'sinstall().Current behavior:
module/fish.module.sh'sinstall()doescp -r "${_src}" "${HOME}/.config/fish"once;upgrade()only reinstalls fisher plugins and never re-copies the config directory. So once a machine is bootstrapped, its deployedconf.d/keychain.fishnever resyncs from the repo template again — any repo-side fix (or any local drift) has no automatic propagation path in either direction.keychain.fish(still in the repo template, unchanged) parsesIdentityFileentries out of~/.ssh/configviaawk, and callskeychain --eval $keys | source(first terminal per login, gated by a$XDG_RUNTIME_DIR/keychain.shownmarker) orkeychain --quiet --eval $keys | source(subsequent terminals).~/.ssh/configon LG14 had CRLF line endings, so the awk-extracted path carried a trailing\r, andkeychain's[ -f "$pm_k" ]check failed. Converting the file to LF fixed it — this was a personal dotfile issue, not something the template caused./usr/bin/keychainsource (ssh_listmissing, ~line 1030): keychain already fingerprints the running agent's loaded keys viassh-add -lbefore deciding whether to prompt, so it only invokesssh-add(and only then shows a passphrase prompt) for keys not already loaded. The marker-file split in the template is therefore purely a verbose/quiet banner-text toggle — it has no effect on when the passphrase prompt itself appears.What changed locally (uncommitted nowhere, deployed-file only):
~/.config/fish/conf.d/keychain.fishon LG14 was rewritten to drop the marker/verbose-vs-quiet split (functionally a no-op simplification per the above) and keepkeychain --quiet --eval $keys | sourceunconditionally, so first-terminal-per-login still auto-prompts for the passphrase and later terminals silently share the already-unlocked agent. This matches the desired UX ("open a terminal → if the key isn't unlocked yet, prompt right there; once unlocked, every other terminal shares it"). This edit was not ported back tomodule/config/fish/conf.d/keychain.fish, so it is currently local-only drift on one machine.Decision needed:
module/config/fish/conf.d/keychain.fishbe updated to the simplified form (drop the marker/quiet split), or is the marker's verbose-once UX intentional and worth keeping as-is?module/fish.module.shneed a resync mechanism (upgrade()re-droppingconf.d/specifically, or something like the bidirectionalsync_config.shidea from feat(tool): sync_config.sh — bidirectional config sync between repo and ~/.config #308) so template fixes actually reach already-bootstrapped machines, and so ad hoc local edits either get captured back or are at least flagged as drift instead of silently persisting forever?setup_secrets.sh ssh-key load(issue feat(secrets): setup_secrets.sh - backend abstraction + ssh-key subcommands (Sec 14, AC-20) #44, AC-20 — passphrase entry owned byssh-addon its own tty, this repo's actual tested/audited tool for this exact action) instead of relying onkeychain's internalssh-addcall, for consistency with the rest of the secrets tooling? Or is delegating tokeychain(which already does the equivalent fingerprint-check-then-add-if-missing dance) an acceptable, simpler alternative?192.168.10.10(and any other bootstrapped machine) need an explicit one-off resync of this file once a decision is made, given there's currently no automated path to get it there?Key interfaces:
module/config/fish/conf.d/keychain.fish— the tracked templatemodule/fish.module.sh—_install_fish_config(cp -r, install-only, no upgrade resync)setup_secrets.sh/lib/secrets.sh— existingssh-key loadsubcommand (issue feat(secrets): setup_secrets.sh - backend abstraction + ssh-key subcommands (Sec 14, AC-20) #44)~/.ssh/config— per-machine, not a repo file; CRLF/permissions hygiene here is out of scope for this issue (personal dotfile, not template-caused)Out of scope:
~/.ssh/config/ repo-tracked-personal-data problem — already tracked in refactor(ssh-config): stop version-controlling personal ssh_config; separate secrets from repo template #278, unrelated file~/.ssh/configpermissions or CRLF cleanup — personal dotfile hygiene, not a repo template concern