Link the agent half of user/ on the Mac mini

Manifest lines can now name an OS. The SSH config, pwswitch and espanso are
Linux only, so link-user on the Mac links CLAUDE.md, rules, skills and the
opencode commands and nothing else. link-mcp no longer aborts under the Mac's
bash 3.2 when a server has no token.
This commit is contained in:
Gabriel Brown committed 2026-11-01 12:41:58 -05:00
1 parent 27e28b0dd1
commit d5ef335d61
5 files changed
+33 -9

No files matched your search

+5 -2
View File
@@ -157,14 +157,17 @@ while read -r name transport target token_var _rest; do
continue
fi
# ${args[@]+...} rather than "${args[@]}": the Mac's bash 3.2 treats an
# empty array as unset under set -u and aborts the whole stage.
#
# Re-registering is how a new server or a rotated token reaches the
# runtime. Removing first avoids the CLI refusing a name it already knows.
# Neither call may print the token, so both are quiet unless they fail.
claude mcp remove "$name" -s user >/dev/null 2>&1 || true
if [[ "$transport" == stdio ]]; then
add=(claude mcp add "$name" -s user "${args[@]}" -- "$launcher")
add=(claude mcp add "$name" -s user ${args[@]+"${args[@]}"} -- "$launcher")
else
add=(claude mcp add --transport "$transport" "$name" "$url" "${args[@]}" -s user)
add=(claude mcp add --transport "$transport" "$name" "$url" ${args[@]+"${args[@]}"} -s user)
fi
if "${add[@]}" >/dev/null 2>&1; then
log "Registered $name."
+3 -1
View File
@@ -69,10 +69,12 @@ displace() {
linked=0
copied=0
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
while read -r kind source destination; do
while read -r kind source destination only_on _rest; do
[[ -n "${kind:-}" ]] || continue
[[ "$kind" == \#* ]] && continue
[[ -z "${only_on:-}" || "$only_on" == "$os" ]] || continue
src="$USER_DIR/$source"
dst="${destination/#\~/$HOME}"
+9 -1
View File
@@ -46,13 +46,15 @@ done < <(find "$repo_dir/user" -type f \( -name 'id_*' -o -name '*.pem' -o -name
# ── Every manifest line is usable ───────────────────────────────────────────
while read -r kind source destination; do
while read -r kind source destination only_on; do
[[ -e "$repo_dir/user/$source" ]] \
|| note "the manifest points at $source, which is not in user/"
[[ "$kind" == link || "$kind" == linkdir || "$kind" == copy ]] \
|| note "the manifest uses an unknown kind: $kind"
[[ "$destination" == '~/'* ]] \
|| note "the manifest destination $destination is not under the home directory"
[[ -z "$only_on" || "$only_on" == linux || "$only_on" == darwin ]] \
|| note "the manifest names an unknown os: $only_on"
done < <(grep -vE '^\s*(#|$)' "$manifest")
# ── The behaviour, against a fake home ──────────────────────────────────────
@@ -77,6 +79,7 @@ linkdir agents/skills ~/.agents/skills
linkdir agents/skills ~/.claude/skills
copy plain.txt ~/.config/plain.txt
link missing.txt ~/.config/missing.txt
copy plain.txt ~/.config/elsewhere.txt nosuchos
FIXTURE
home="$work/home"
@@ -141,6 +144,11 @@ fi
grep -q 'missing.txt' "$work/log" \
|| note 'a skipped manifest entry was not reported'
# A line naming another OS is for another machine. The Mac takes the agent half
# of user/ and none of the Linux desktop half.
[[ -e "$home/.config/elsewhere.txt" ]] \
&& note 'a manifest entry for another OS was applied here'
# ── The answer sticks ───────────────────────────────────────────────────────
#
# So that `panama upgrade` on a configured machine relinks without an interview,
+6
View File
@@ -86,6 +86,12 @@ Put the file under `user/`, add a line to `manifest`, run:
Anything already at the destination is moved to `config/old/` rather than
deleted, under a name that says where it came from.
A line can end with `linux` or `darwin` to apply only on that OS. The Mac mini
is not a Panama desktop, but it runs agents, so it takes the agent half of this
directory and skips the SSH config, `pwswitch` and espanso. Panama's shipped
skills describe the Linux desktop, so the Mac runs `link-user` and `link-mcp`
only, never `link-skills`.
## What does not go in here
Anything secret. This repository is readable by anyone who finds it, and the
+10 -5
View File
@@ -1,6 +1,6 @@
# What in user/ goes where, and in what form.
#
# <kind> <source under user/> <destination>
# <kind> <source under user/> <destination> [os]
#
# kind is one of:
# link symlink the destination at the source, so editing either edits the
@@ -14,6 +14,10 @@
# copy copy once, and never touch it again if the destination exists. Use
# this for files a machine legitimately diverges on.
#
# os is optional: linux or darwin, matched against `uname -s`. A line naming
# one is skipped everywhere else. Leave it off for anything every machine
# wants, which is most of this file; the Mac mini only takes the agent half.
#
# Lines beginning with # are comments and blank lines are ignored. ~ in a
# destination is this user's home.
#
@@ -43,21 +47,22 @@ link agents/rules ~/.claude/rules
# ── SSH ──────────────────────────────────────────────────────────────────────
# Host aliases only. Keys are per-machine and are never tracked; this is the
# file that makes `ssh server` work the moment a machine is set up, and it is
# what the SSH Hosts launcher command reads.
link ssh/config ~/.ssh/config
# what the SSH Hosts launcher command reads. Linux only: it names id_ed25519
# and the desktop keyring's agent socket, and the Mac has neither.
link ssh/config ~/.ssh/config linux
# ── Scripts ──────────────────────────────────────────────────────────────────
# Personal commands wanted on every machine, desktop or server. ~/.local/bin is
# on PATH in both shell configs. pwswitch toggles passwordless sudo through a
# sudoers.d drop-in, so an agent can run sudo and the password comes back after.
link bin/pwswitch ~/.local/bin/pwswitch
link bin/pwswitch ~/.local/bin/pwswitch linux
# ── Espanso ──────────────────────────────────────────────────────────────────
# The personal expansion triggers. Copied rather than linked, because this is a
# file each machine may add its own triggers to. It lands before setup-identity
# runs, and that stage only seeds a file that does not exist yet, so what is
# tracked here wins over the name and email the interview would have written.
copy espanso/identity.yml ~/.config/espanso/match/identity.yml
copy espanso/identity.yml ~/.config/espanso/match/identity.yml linux
# ── OpenCode ─────────────────────────────────────────────────────────────────
# Claude Code carries its commands and agents as plugins, which opencode cannot